1# Developing Extensions
2
3## Extension Capabilities
4
5Extensions can add the following capabilities to Zed:
6
7- [Languages](./languages.md)
8- [Debuggers](./debugger-extensions.md)
9- [Themes](./themes.md)
10- [Icon Themes](./icon-themes.md)
11- [Slash Commands](./slash-commands.md)
12- [MCP Servers](./mcp-extensions.md)
13
14## Developing an Extension Locally
15
16Before starting to develop an extension for Zed, be sure to [install Rust via rustup](https://www.rust-lang.org/tools/install).
17
18> Rust must be installed via rustup. If you have Rust installed via homebrew or otherwise, installing dev extensions will not work.
19
20When developing an extension, you can use it in Zed without needing to publish it by installing it as a _dev extension_.
21
22From the extensions page, click the `Install Dev Extension` button (or the {#action zed::InstallDevExtension} action) and select the directory containing your extension.
23
24If you need to troubleshoot, you can check the Zed.log ({#action zed::OpenLog}) for additional output. For debug output, close and relaunch zed with the `zed --foreground` from the command line which show more verbose INFO level logging.
25
26If you already have a published extension with the same name installed, your dev extension will override it.
27
28After installing the `Extensions` page will indicate that that the upstream extension is "Overridden by dev extension".
29
30Pre-installed extensions with the same name have to be uninstalled before installing the dev extension. See [#31106](https://github.com/zed-industries/zed/issues/31106) for more.
31
32## Directory Structure of a Zed Extension
33
34A Zed extension is a Git repository that contains an `extension.toml`. This file must contain some
35basic information about the extension:
36
37```toml
38id = "my-extension"
39name = "My extension"
40version = "0.0.1"
41schema_version = 1
42authors = ["Your Name <you@example.com>"]
43description = "My cool extension"
44repository = "https://github.com/your-name/my-zed-extension"
45```
46
47In 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:
48
49```
50my-extension/
51 extension.toml
52 Cargo.toml
53 src/
54 lib.rs
55 languages/
56 my-language/
57 config.toml
58 highlights.scm
59 themes/
60 my-theme.json
61```
62
63## WebAssembly
64
65Procedural 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:
66
67```toml
68[package]
69name = "my-extension"
70version = "0.0.1"
71edition = "2021"
72
73[lib]
74crate-type = ["cdylib"]
75
76[dependencies]
77zed_extension_api = "0.1.0"
78```
79
80Use 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.
81
82In 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:
83
84```rs
85use zed_extension_api as zed;
86
87struct MyExtension {
88 // ... state
89}
90
91impl zed::Extension for MyExtension {
92 // ...
93}
94
95zed::register_extension!(MyExtension);
96```
97
98> `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.
99
100## Forking and cloning the repo
101
1021. Fork the repo
103
104> 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.
105
1062. Clone the repo to your local machine
107
108```sh
109# Substitute the url of your fork here:
110# git clone https://github.com/zed-industries/extensions
111cd extensions
112git submodule init
113git submodule update
114```
115
116## Extension License Requirements
117
118As of October 1st, 2025, extension repositories must include one of the following licenses:
119
120- [MIT](https://opensource.org/license/mit)
121- [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
122
123This allows us to distribute the resulting binary produced from your extension code to our users.
124Without a valid license, the pull request to add or update your extension in the following steps will fail CI.
125
126Your license file should be at the root of your extension repository with a filename like `LICENSE`, `LICENSE.txt`, `LICENSE-MIT`, etc. For the logic on how license files are identified, see the [license validation source code](https://github.com/zed-industries/extensions/blob/main/src/lib/license.js).
127
128> This license requirement applies only to your extension code itself (the code that gets compiled into the extension binary).
129> It does not apply to any tools your extension may download or interact with, such as language servers or other external dependencies.
130> 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.
131
132## Publishing your extension
133
134To publish an extension, open a PR to [the `zed-industries/extensions` repo](https://github.com/zed-industries/extensions).
135
136In your PR, do the following:
137
1381. Add your extension as a Git submodule within the `extensions/` directory
139
140```sh
141git submodule add https://github.com/your-username/foobar-zed.git extensions/foobar
142git add extensions/foobar
143```
144
145> All extension submodules must use HTTPS URLs and not SSH URLS (`git@github.com`).
146
1472. Add a new entry to the top-level `extensions.toml` file containing your extension:
148
149```toml
150[my-extension]
151submodule = "extensions/my-extension"
152version = "0.0.1"
153```
154
155> If your extension is in a subdirectory within the submodule you can use the `path` field to point to where the extension resides.
156
1573. Run `pnpm sort-extensions` to ensure `extensions.toml` and `.gitmodules` are sorted
158
159Once your PR is merged, the extension will be packaged and published to the Zed extension registry.
160
161> Extension IDs and names should not contain `zed` or `Zed`, since they are all Zed extensions.
162
163## Updating an extension
164
165To update 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. Update the extension's submodule to the commit of the new version.
1702. Update the `version` field for the extension in `extensions.toml`
171 - Make sure the `version` matches the one set in `extension.toml` at the particular commit.
172
173If you'd like to automate this process, there is a [community GitHub Action](https://github.com/huacnlee/zed-extension-action) you can use.
174
175> **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.