developing-extensions.md

  1---
  2title: Developing Extensions
  3description: "Create Zed extensions: languages, themes, debuggers, and more."
  4---
  5
  6# Developing Extensions {#developing-extensions}
  7
  8Zed extensions are Git repositories containing an `extension.toml` manifest. They can provide languages, themes, debuggers, snippets, and MCP servers.
  9
 10## Extension Features {#extension-features}
 11
 12Extensions can provide:
 13
 14- [Languages](./languages.md)
 15- [Debuggers](./debugger-extensions.md)
 16- [Themes](./themes.md)
 17- [Icon Themes](./icon-themes.md)
 18- [Snippets](./snippets.md)
 19- [MCP Servers](./mcp-extensions.md)
 20
 21## Developing an Extension Locally
 22
 23Before starting to develop an extension for Zed, be sure to [install Rust via rustup](https://www.rust-lang.org/tools/install).
 24
 25> Rust must be installed via rustup. If you have Rust installed via homebrew or otherwise, installing dev extensions will not work.
 26
 27When developing an extension, you can use it in Zed without needing to publish it by installing it as a _dev extension_.
 28
 29From the extensions page, click the `Install Dev Extension` button (or the {#action zed::InstallDevExtension} action) and select the directory containing your extension.
 30
 31If you need to troubleshoot, check Zed.log ({#action zed::OpenLog}) for additional output. For debug output, close and relaunch Zed from the command line with `zed --foreground`, which shows more verbose INFO-level logs.
 32
 33If you already have the published version of the extension installed, the published version will be uninstalled prior to the installation of the dev extension. After successful installation, the `Extensions` page will indicate that the upstream extension is "Overridden by dev extension".
 34
 35## Directory Structure of a Zed Extension
 36
 37A Zed extension is a Git repository that contains an `extension.toml`. This file must contain some
 38basic information about the extension:
 39
 40```toml
 41id = "my-extension"
 42name = "My extension"
 43version = "0.0.1"
 44schema_version = 1
 45authors = ["Your Name <you@example.com>"]
 46description = "Example extension"
 47repository = "https://github.com/your-name/my-zed-extension"
 48```
 49
 50In addition to this, there are several other optional files and directories that can be used to add functionality to a Zed extension. An example directory structure of an extension that provides all capabilities is as follows:
 51
 52```
 53my-extension/
 54  extension.toml
 55  Cargo.toml
 56  src/
 57    lib.rs
 58  languages/
 59    my-language/
 60      config.toml
 61      highlights.scm
 62  themes/
 63    my-theme.json
 64  snippets/
 65    snippets.json
 66    rust.json
 67```
 68
 69## WebAssembly
 70
 71Procedural parts of extensions are written in Rust and compiled to WebAssembly. To develop an extension that includes custom code, include a `Cargo.toml` like this:
 72
 73```toml
 74[package]
 75name = "my-extension"
 76version = "0.0.1"
 77edition = "2021"
 78
 79[lib]
 80crate-type = ["cdylib"]
 81
 82[dependencies]
 83zed_extension_api = "0.1.0"
 84```
 85
 86Use the latest version of the [`zed_extension_api`](https://crates.io/crates/zed_extension_api) available on crates.io. Make sure it's still [compatible with Zed versions](https://github.com/zed-industries/zed/blob/main/crates/extension_api#compatible-zed-versions) you want to support.
 87
 88In the `src/lib.rs` file in your Rust crate you will need to define a struct for your extension and implement the `Extension` trait, as well as use the `register_extension!` macro to register your extension:
 89
 90```rs
 91use zed_extension_api as zed;
 92
 93struct MyExtension {
 94    // ... state
 95}
 96
 97impl zed::Extension for MyExtension {
 98    // ...
 99}
100
101zed::register_extension!(MyExtension);
102```
103
104> `stdout`/`stderr` is forwarded directly to the Zed process. In order to see `println!`/`dbg!` output from your extension, you can start Zed in your terminal with a `--foreground` flag.
105
106## Forking and cloning the repo
107
1081. Fork the repo
109
110> **Note:** It is very helpful if you fork the `zed-industries/extensions` repo to a personal GitHub account instead of a GitHub organization, as this allows Zed staff to push any needed changes to your PR to expedite the publishing process.
111
1122. Clone the repo to your local machine
113
114```sh
115# Substitute the url of your fork here:
116# git clone https://github.com/zed-industries/extensions
117cd extensions
118git submodule init
119git submodule update
120```
121
122## Extension License Requirements
123
124As of October 1st, 2025, extension repositories must include a license.
125The following licenses are accepted:
126
127- [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
128- [BSD 2-Clause](https://opensource.org/license/bsd-2-clause)
129- [BSD 3-Clause](https://opensource.org/license/bsd-3-clause)
130- [CC BY 4.0](https://creativecommons.org/licenses/by/4.0)
131- [GNU GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)
132- [GNU LGPLv3](https://www.gnu.org/licenses/lgpl-3.0.en.html)
133- [MIT](https://opensource.org/license/mit)
134- [Unlicense](https://unlicense.org)
135- [zlib](https://opensource.org/license/zlib)
136
137This allows us to distribute the resulting binary produced from your extension code to our users.
138Without a valid license, the pull request to add or update your extension in the following steps will fail CI.
139
140Your license file should be at the root of your extension repository. Any filename that has `LICENCE` or `LICENSE` as a prefix (case insensitive) will be inspected to ensure it matches one of the accepted licenses. See the [license validation source code](https://github.com/zed-industries/extensions/blob/main/src/lib/license.js).
141
142> This license requirement applies only to your extension code itself (the code that gets compiled into the extension binary).
143> It does not apply to any tools your extension may download or interact with, such as language servers or other external dependencies.
144> If your repository contains both extension code and other projects (like a language server), you are not required to relicense those other projects — only the extension code needs to be one of the aforementioned accepted licenses.
145
146## Extension Publishing Prerequisites
147
148Before publishing your extension, make sure that you have chosen a unique extension ID for your extension in the [extension manifest](#directory-structure-of-a-zed-extension).
149This will be the primary identifier for your extension and cannot be changed after your extension has been published.
150Also, ensure that you have filled out all the required fields in the manifest.
151
152Furthermore, please make sure that your extension fulfills the following preconditions before you move on to publishing your extension:
153
154- Extension IDs and names must not contain the words `zed`, `Zed` or `extension`, since they are all Zed extensions.
155- Your extension ID should provide some information on what your extension tries to accomplish. E.g. for themes, it should be suffixed with `-theme`, snippet extensions should be suffixed with `-snippets` and so on. An exception to that rule are extension that provide support for languages or popular tooling that people would expect to find under that ID. You can take a look at the list of [existing extensions](https://github.com/zed-industries/extensions/blob/main/extensions.toml) to get a grasp on how this usually is enforced.
156- Extensions should provide something that is not yet available in the marketplace as opposed to fixing something that could be resolved within an existing extension. For example, if you find that an existing extension's support for a language server is not functioning properly, first try contributing a fix to the existing extension as opposed to submitting a new extension immediately.
157  - If you receive no response or reaction within the upstream repository within a reasonable amount of time, feel free to submit a pull request that aims to fix said issue. Please ensure that you provide your previous efforts within the pull request to the extensions repository for adding your extension. Zed maintainers will then decide on how to proceed on a case by case basis.
158- Extensions that intend to provide a language, debugger or MCP server must not ship the language server as part of the extension. Instead, the extension should either download the language server or check for the availability of the language server in the users environment using the APIs as provided by the [Zed Rust Extension API](https://docs.rs/zed_extension_api/latest/zed_extension_api/).
159- Themes and icon themes should not be published as part of extensions that provide other features, e.g. language support. Instead, they should be published as a distinct extension. This also applies to theme and icon themes living in the same repository.
160
161Note that non-compliance will be raised during the publishing process by reviewers and delay the release of your extension.
162
163## Publishing your extension
164
165To publish an extension, open a PR to [the `zed-industries/extensions` repo](https://github.com/zed-industries/extensions).
166
167In your PR, do the following:
168
1691. Add your extension as a Git submodule within the `extensions/` directory under the `extensions/{extension-id}` path
170
171```sh
172git submodule add https://github.com/your-username/foobar-zed.git extensions/my-extension
173git add extensions/my-extension
174```
175
176> All extension submodules must use HTTPS URLs and not SSH URLS (`git@github.com`).
177
1782. Add a new entry to the top-level `extensions.toml` file containing your extension:
179
180```toml
181[my-extension]
182submodule = "extensions/my-extension"
183version = "0.0.1"
184```
185
186If your extension is in a subdirectory within the submodule, you can use the `path` field to point to where the extension resides:
187
188```toml
189[my-extension]
190submodule = "extensions-my-extension"
191path = "packages/zed"
192version = "0.0.1"
193```
194
195> Note that the [required extension license](#extension-license-requirements) must reside at the specified path, a license at the root of the repository will not work. However, you are free to symlink an existing license within the repository or choose an alternative license from the list of accepted licenses for the extension code.
196
1973. Run `pnpm sort-extensions` to ensure `extensions.toml` and `.gitmodules` are sorted
198
199Once your PR is merged, the extension will be packaged and published to the Zed extension registry.
200
201## Updating an extension
202
203To update an extension, open a PR to [the `zed-industries/extensions` repo](https://github.com/zed-industries/extensions).
204
205In your PR do the following:
206
2071. Update the extension's submodule to the commit of the new version. For this, you can run
208
209```sh
210# From the root of the repository:
211git submodule update --remote extensions/your-extension-name
212```
213
214to update your extension to the latest commit available in your remote repository.
215
2162. Update the `version` field for the extension in `extensions.toml`
217   - Make sure the `version` matches the one set in `extension.toml` at the particular commit.
218
219If you'd like to automate this process, there is a [community GitHub Action](https://github.com/huacnlee/zed-extension-action) you can use.
220
221> **Note:** If your extension repository has a different license, you'll need to update it to be one of the [accepted extension licenses](#extension-license-requirements) before publishing your update.