Jump to content

Zed: Difference between revisions

From NixOS Wiki
Clarify nixGL wrapper is needed for Zed.
Layer-09 (talk | contribs)
mNo edit summary
 
(5 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<languages/>
{{infobox application
  |name=Zed
  |image=Zed_Editor_Logo.png
  |type=Source-code Editor
  |developer=Zed Industries
  |predecessor=Atom
  |status=Active
  |license=[https://www.gnu.org/licenses/agpl-3.0.html AGPL], [https://www.gnu.org/licenses/gpl-3.0.html GPL], [https://www.apache.org/licenses/LICENSE-2.0 Apache License]
  |os=Cross-platform (Linux, macOS, Windows)
  |platform=Desktop
  |programmingLanguage=Rust
  |website=[https://zed.dev zed.dev]
  |github=zed-industries/zed
  |bugTracker=[https://github.com/zed-industries/zed/issues GitHub Issues]
  |documentation=[https://zed.dev/docs Zed Documentation]
}}
<translate>
<!--T:1-->
[https://zed.dev Zed]<ref>Zed Industries, "Zed", Official Website, Accessed October 2025. https://zed.dev</ref> is a collaborative, GPU-accelerated text editor developed by Zed Industries. It combines fast local editing with real-time multiplayer features and ships with batteries-included tooling for popular programming languages.
</translate>
<translate>
<!--T:2-->
The editor provides native builds for Linux, including Nixpkgs packages and a reproducible flake. Hardware acceleration requires a GPU with Vulkan support; systems without Vulkan can fall back to emulation via tools such as [https://github.com/nix-community/nixGL nixGL].<ref>Zed Industries, "Linux", Zed Documentation, Accessed October 2025. https://zed.dev/docs/linux</ref>
</translate>


[https://zed.dev/ Zed] is a graphical text editor focusing on speed and collaborative editing.
<translate>
== Installation == <!--T:3-->


Its Linux support is fairly recent, the NixOS support even more so.
==== Shell ==== <!--T:4-->
</translate>
{{code|lang=bash|line=no|1=$ nix-shell -p zed-editor}}
<translate>
<!--T:5-->
The <code>zed-editor</code> package is available in Nixpkgs from channel 24.11 onward. The command above provides <code>zed-editor</code> in the current shell session without modifying any configuration files.


== Installation ==
<!--T:6-->
The package zed-editor is available only from channel 24.11 onward.
The package installs both desktop launchers and a CLI entry point aliased to <code>zeditor</code>, mirroring the upstream binary name.


CLI support is installed and aliased to <code>zeditor</code>
==== System setup ==== <!--T:7-->
</translate>
{{code|lang=nix|line=no|1=# In /etc/nixos/configuration.nix
environment.systemPackages = [
  pkgs.zed-editor
];


Zed requires a GPU with Vulkan support, otherwise it will prompt you to use a very inefficient "emulated GPU" mode. This is available thru `nixGL` by using the Vulkan wrappers, or via home-manager nixGL integration by setting the <code>nixGL.vulkan.enable = true</code>.
# In home-manager configuration (home.nix)
On non-NixOS systems this method of providing Vulkan support via NixGL has even been demonstrated that it can be more consistent/stable than relying on native host system support. The Vulkan libraries of Ubuntu 24.04 for example don't provide the same level of support between X11 and Wayland environments, and don't meet the Zed minimum Vulkan API requirements under X11, but the nixGL wrapper with Vulkan support does (for a GPU that actually supports the features).
home.packages = [
  pkgs.zed-editor
];
}}
<translate>
<!--T:8-->
Rebuild your system or Home Manager profile to make Zed available persistently. On NixOS, run <code>sudo nixos-rebuild switch</code>; for Home Manager, run <code>home-manager switch</code>.


== LSP Support ==
==== Flake ==== <!--T:9-->
By default, Zed will try to download pre-built LSP servers in <code>~/.local/share/zed/languages/</code>. This does not work for NixOS.


There's sadly no way to inject those from <code>$PATH</code> for now. Worse, the way to point to the language server is language-specific, there is no global configuration flag for now.
<!--T:10-->
Zed maintains an official flake for tracking the latest upstream build. This approach is useful if you need features that have not yet reached stable Nixpkgs.
</translate>
{{code|lang=nix|line=no|1=inputs.zed.url = "github:zed-industries/zed";


The following sections contain some language-specific setup working on NixOS.
outputs = { self, nixpkgs, zed, ... }@inputs: let
  system = "x86_64-linux";
  pkgs = import nixpkgs { inherit system; };
in {
  packages.${system}.zed-latest = zed.packages.${system}.default;
};}}
<translate>
<!--T:11-->
Build the flake package with <code>nix build .#zed-latest</code> or expose it in your configuration with the appropriate overlay.
</translate>
{{Warning|Zed requires hardware-accelerated Vulkan. On systems without supported drivers, use <code>nixGL</code> or home-manager's <code>nixGL.vulkan.enable {{=}} true;</code> to provide the necessary libraries.}}
<translate>
<!--T:12-->
Providing Vulkan through <code>nixGL</code> can be more consistent than relying on host distribution packages, especially on non-NixOS systems where Wayland and X11 stacks differ in their Vulkan capabilities.


=== rust-analyzer ===
== Configuration == <!--T:13-->
Here, we'll assume rust-analyzer is globally installed in your system profile at <code>/run/current-system/sw/bin/rust-analyzer</code>. You may want to adapt this path in the following code snippet to something more relevant to your use case.


Add the following snippet to your zed configuration file:<syntaxhighlight lang="json">
<!--T:14-->
"lsp": {
Zed stores its configuration in JSON files under <code>~/.config/zed</code>. Home Manager can manage these settings declaratively.
  "rust-analyzer": {
    "binary": {
      "path": "/run/current-system/sw/bin/rust-analyzer",
    },
  }
}
</syntaxhighlight>


== Remote Server ==
==== Basic ==== <!--T:15-->
When connecting to a remote server running NixOS, Zed will either automatically download a static server binary matching its version from the upstream Zed website onto the remote host, or will locally obtain then upload a static server binary (if <code>"upload_binary_over_ssh": true</code>) to the remote host, before connecting to it :
</translate>
{{code|lang=nix|line=no|1=programs.zed-editor = {
  enable = true;
  extensions = [ "nix" "toml" "rust" ];
  userSettings = {
    theme = {
      mode = "system";
      dark = "One Dark";
      light = "One Light";
    };
    hour_format = "hour24";
    vim_mode = true;
  };
};}}
<translate>
<!--T:16-->
The configuration above enables Zed via Home Manager, installs a small set of extensions, and synchronises the theme with the desktop appearance.


:<syntaxhighlight lang="console">
==== Advanced ==== <!--T:17-->
➜  ~ ls .zed_server
</translate>
zed-remote-server-stable-0.169.2
{{code|lang=nix|line=no|1=
➜  ~ file .zed_server/zed-remote-server-stable-0.169.2
programs.zed-editor = {
.zed_server/zed-remote-server-stable-0.169.2: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=b1ac2c83127e7a9a072840cd7c24d7d125c1b655, not stripped
  enable = true;
➜  ~ ldd .zed_server/zed-remote-server-stable-0.169.2
statically linked
</syntaxhighlight>


In either case, the binary is placed in the <code>~/.zed_server</code> folder on the remote system, and must match the client Zed version exactly or the connection will fail.  This same <code>~/.zed_server</code> location on the client system is also where locally downloaded binaries are stored before being uploaded via SSH to a remote system. 
  # This populates the userSettings "auto_install_extensions"
  extensions = [ "nix" "toml" "elixir" "make" ];


While the default prebuilt binaries from the upstream Zed website work fine with the default nixpkgs definition of <code>zed-editor</code>, you may want to provide your own, whether for reasons related to custom patching or purely mistrust of prebuilt upstream binaries.
  # Everything inside of these brackets are Zed options
  userSettings = {
    assistant = {
      enabled = true;
      version = "2";
      default_open_ai_model = null;


The <code>zed-editor</code> provides an additional output, <code>remote_server</code>, for the server binary matching the client version. To make use of it you need the binary in <code>"${pkgs.zed-editor.remote_server}/bin"</code> placed/symlinked into your <code>~/.zed_server</code> folder (and <code>"upload_binary_over_ssh": true</code> included in the Zed client settings that specify each remote system). 
      # Provider options:
      # - zed.dev models (claude-3-5-sonnet-latest) requires GitHub connected
      # - anthropic models (claude-3-5-sonnet-latest, claude-3-haiku-latest, claude-3-opus-latest) requires API_KEY
      # - copilot_chat models (gpt-4o, gpt-4, gpt-3.5-turbo, o1-preview) requires GitHub connected
      default_model = {
        provider = "zed.dev";
        model = "claude-3-5-sonnet-latest";
      };


In a simple case, this can be setup with home-manager as follows:
      # inline_alternatives = [
      #  {
      #    provider = "copilot_chat";
      #    model = "gpt-3.5-turbo";
      #  }
      # ];
    };


:<syntaxhighlight lang="nix">
    node = {
{ pkgs, ... }:
      path = lib.getExe pkgs.nodejs;
{
      npm_path = lib.getExe' pkgs.nodejs "npm";
  home.file.".zed_server" = {
     };
    source = "${pkgs.zed-editor.remote_server}/bin";
     # keeps the folder writable, but symlinks the binaries into it
    recursive = true;
  };
}
</syntaxhighlight>


Because the <code>~/.zed_server</code> folder is also used for external clients connecting to the current system as a remote, it's necessary to use the <code>recursive = true;</code> setting so only individual binaries are symlinked from the nix store into the folder, and the folder itself remains writable. When a client connects using a version that doesn't already have a matching server binary available, it will use its configured method to add the missing server binary.  This same configuration may be set more easily via home-manager if you're managing your entire Zed config thru home-manager by setting <code>programs.zed-editor.installRemoteServer = true;</code> (the <code>programs.zed-editor.enable = true</code> must also be enabled for this to take effect, see below for further details about using the home-manager <code>programs.zed-editor</code>). 
    hour_format = "hour24";
    auto_update = false;


If you want to prohibit clients from managing the Zed server binaries on your system when connecting to it as a remote, you can make the whole <code>~/.zed_server</code> folder read-only by symlinking the whole folder to the nix store. This will restrict clients to only be able to use one Zed server binary provided from your nixpkgs <code>zed-editor</code>, which has the indirect effect of also limiting to a single Zed client version that's allowed to connect. To do this, simply remove the <code>recursive = true;</code> or explicitly set it to <code>recursive = false;</code> (the default when not specified) on <code>home.file.".zed_server"</code>.
    terminal = {
Be aware however that Zed will refuse to connect to a remote if there is no remote server binary matching the exact Zed client version and it's unable to populate a matching one!
      alternate_scroll = "off";
      blinking = "off";
      copy_on_select = false;
      dock = "bottom";
      detect_venv = {
        on = {
          directories = [ ".env" "env" ".venv" "venv" ];
          activate_script = "default";
        };
      };
      env = {
        TERM = "alacritty";
      };
      font_family = "FiraCode Nerd Font";
      font_features = null;
      font_size = null;
      line_height = "comfortable";
      option_as_meta = false;
      button = false;
      shell = "system";
      # shell = {
      #  program = "zsh";
      # };
      toolbar = {
        title = true;
      };
      working_directory = "current_project_directory";
    };


== Home manager support ==
    lsp = {
Zed is supported by home-manager, which allows you to make a reproducible initial Zed setup.
      rust-analyzer = {
However, due to the method Zed uses for installing, running, and managing Extensions, only the initial set of preinstalled extensions can currently be defined in home-manager. It's possible to install additional extensions from the Zed GUI on any system without including it in the home-manager config. This is partially a technical limitation of the format of extensions (which follow a similar model to VSCode and require external binaries to be downloaded and used at run-time}, and a Zed extensions management design (that doesn't track the installed extensions in the settings but does allow a list to be manually added that will be auto-installed if not already present). 
        binary = {
          # path = lib.getExe pkgs.rust-analyzer;
          path_lookup = true;
        };
      };


The <code>userSettings</code> and <code>userkeyMaps</code> options will be translated directly into JSON. 
      nix = {
The <code>extensions</code> currently just defines the <code>userSettings.auto_install_extensions</code> (see Zed documentation).
        binary = {
The <code>extraPackages</code> includes extra nixpkgs in the environment Zed executes in (an FHS), so extra LSP server packages (e.g. <code>pkgs.nixd</code>) or optional tools for LSP servers (e.g. <code>pkgs.shellcheck</code> for the "Basher" LSP) should be included. 
          path_lookup = true;
        };
      };


Note that home-manager configuration produces a <b>read only <code>settings.json</code></b>, but Zed <b>assumes/requires the <code>settings.json</code> to be writable</b>. Using home-manager configuration will prevent you from changing most settings in the GUI since Zed will be unable to modify the read-only <code>settings.json</code> accordingly.  This includes the current/default AI engine to use, or even switching the model of the AI engine (as well as most non-AI settings).
      elixir-ls = {
        binary = {
          path_lookup = true;
        };
        settings = {
          dialyzerEnabled = true;
        };
      };
    };


You can see an example of the home-manager configuration:
    languages = {
      "Elixir" = {
:<syntaxhighlight lang="nix">
        language_servers = [ "!lexical" "elixir-ls" "!next-ls" ];
{pkgs, lib, ... }:
        format_on_save = {
          external = {
            command = "mix";
            arguments = [ "format" "--stdin-filename" "{buffer_path}" "-" ];
          };
        };
      };


{
      "HEEX" = {
    programs.zed-editor = {
        language_servers = [ "!lexical" "elixir-ls" "!next-ls" ];
         enable = true;
        format_on_save = {
          external = {
            command = "mix";
            arguments = [ "format" "--stdin-filename" "{buffer_path}" "-" ];
          };
         };
      };
    };


        ## This populates the userSettings "auto_install_extensions"
    vim_mode = true;
        extensions = ["nix" "toml" "elixir" "make"];


        ## everything inside of these brackets are Zed options.
    # Tell Zed to use direnv and direnv can use a flake.nix environment
        userSettings = {
    load_direnv = "shell_hook";
    base_keymap = "VSCode";


            assistant = {
    theme = {
                enabled = true;
      mode = "system";
                version = "2";
      light = "One Light";
                default_open_ai_model = null;
      dark = "One Dark";
                ### PROVIDER OPTIONS
    };
                ### zed.dev models { claude-3-5-sonnet-latest } requires github connected
                ### anthropic models { claude-3-5-sonnet-latest claude-3-haiku-latest claude-3-opus-latest  } requires API_KEY
                ### copilot_chat models { gpt-4o gpt-4 gpt-3.5-turbo o1-preview } requires github connected
                default_model = {
                    provider = "zed.dev";
                    model = "claude-3-5-sonnet-latest";
                };


                #                inline_alternatives = [
    show_whitespaces = "all";
                #                    {
    ui_font_size = 16;
                #                        provider = "copilot_chat";
    buffer_font_size = 16;
                #                        model = "gpt-3.5-turbo";
  };
                #                    }
};
                #                ];
}}
            };
<translate>
<!--T:18-->
This example adds language servers to the FHS sandbox, enables the bundled assistant, configures the terminal, and ensures remote server binaries are provided declaratively.


            node = {
<!--T:19-->
                path = lib.getExe pkgs.nodejs;
The <code>userSettings</code> and <code>userKeyMaps</code> options translate directly into JSON. The <code>extraPackages</code> option includes additional Nixpkgs in the FHS environment, useful for LSP servers (e.g., <code>pkgs.nixd</code>) or optional tools (e.g., <code>pkgs.shellcheck</code> for the Basher LSP).
                npm_path = lib.getExe' pkgs.nodejs "npm";
            };


            hour_format = "hour24";
<!--T:20-->
            auto_update = false;
Home Manager renders <code>settings.json</code> as read-only, which prevents Zed's GUI from saving most preference changes, including AI provider selection. Plan to manage long-term settings declaratively or temporarily disable the module when editing interactively.
            terminal = {
                alternate_scroll = "off";
                blinking = "off";
                copy_on_select = false;
                dock = "bottom";
                detect_venv = {
                    on = {
                        directories = [".env" "env" ".venv" "venv"];
                        activate_script = "default";
                    };
                };
                env = {
                    TERM = "alacritty";
                };
                font_family = "FiraCode Nerd Font";
                font_features = null;
                font_size = null;
                line_height = "comfortable";
                option_as_meta = false;
                button = false;
                shell = "system";
                #{
                #                    program = "zsh";
                #};
                toolbar = {
                    title = true;
                };
                working_directory = "current_project_directory";
            };


<!--T:21-->
Only the initial extension list can be defined declaratively; additional extensions installed through the GUI are stored within Zed's writable data directories and do not appear in <code>userSettings</code>. This follows a similar model to VSCode, where extensions require external binaries downloaded at runtime.
</translate>


== LSP support ==
<translate>
<!--T:22-->
Zed downloads language servers into <code>~/.local/share/zed/languages/</code>, which is read-only on NixOS. Instead, use declarative methods to supply LSP binaries.
</translate>
<translate>
<!--T:23-->
Check <strong>LSP Logs → Server Info</strong> to confirm which binaries are running. Prefer language servers packaged in Nixpkgs so that dependencies are resolved within the Nix store.
</translate>


            lsp = {
==== Nix-ld (recommended) ====
                rust-analyzer = {
<translate>
<!--T:24-->
Enable [[FAQ#I've downloaded a binary, but I can't run it, what can I do?|<code>nix-ld</code>]] so prebuilt language servers can resolve dynamic libraries without wrapping.
</translate>


                    binary = {
==== FHS wrapper ====
                        #                        path = lib.getExe pkgs.rust-analyzer;
<translate>
                        path_lookup = true;
<!--T:25-->
                    };
Use <code>pkgs.zed-editor.fhsWithPackages</code> to extend the FHS environment with additional system libraries when a language server requires them.
                };
</translate>
                nix = {
{{code|lang=nix|line=no|1=pkgs.zed-editor.fhsWithPackages (pkgs: with pkgs; [ openssl zlib ])}}
                    binary = {
<translate>
                        path_lookup = true;
<!--T:26-->
                    };  
Remember that language servers started inside the wrapper do not automatically inherit tools from ad-hoc shells; include every dependency declaratively.
                };
</translate>


                elixir-ls = {
==== Bring your own LSP servers ====
                    binary = {
<translate>
                        path_lookup = true;  
<!--T:27-->
                    };
Newer versions of Zed can detect LSP servers installed in <code>PATH</code> and prefer local versions over automatically downloaded ones. Install LSP servers globally or provide them through nix shell.
                    settings = {
</translate>
                        dialyzerEnabled = true;
<translate>
                    };
<!--T:28-->
                };
Nixpkgs versions of tools may be required for development on NixOS, especially for the C/C++ ecosystem. Check <strong>LSP Logs → Server Info</strong> to see which binaries are running.
            };
</translate>
<translate>
<!--T:29-->
If automatic detection doesn't work, specify the path manually in your Zed configuration:
</translate>
{{code|lang=json|line=no|1={
  "lsp": {
    "rust-analyzer": {
      "binary": {
        "path": "/run/current-system/sw/bin/rust-analyzer"
      }
    }
  }
}
}}
<translate>
<!--T:30-->
Adjust the path for each language server you manage. The example above assumes rust-analyzer is installed in your system profile.
</translate>
== Remote server ==
<translate>
<!--T:31-->
Zed uploads a versioned remote server binary to <code>~/.zed_server</code> on the target host. The Nixpkgs package exposes the matching binary via the <code>remote_server</code> output.
</translate>
<translate>
<!--T:32-->
When you connect to a remote machine, the client either downloads a matching server binary from upstream or pushes a local copy if <code>"upload_binary_over_ssh": true</code> is enabled. Connections fail if the versions diverge.
</translate>
{{code|lang=nix|line=no|1=home.file.".zed_server" = {
  source = "${pkgs.zed-editor.remote_server}/bin";
  recursive = true;
};}}
<translate>
<!--T:33-->
The <code>recursive = true;</code> setting keeps the directory writable while symlinking individual binaries, allowing Zed to add new versions when needed. This is necessary because the <code>~/.zed_server</code> folder is also used when external clients connect to the current system as a remote.
</translate>
<translate>
<!--T:34-->
Alternatively, use Home Manager's built-in option for simpler setup:
</translate>
{{code|lang=nix|line=no|1=programs.zed-editor = {
  enable = true;
  installRemoteServer = true;
};}}
<translate>
<!--T:35-->
To restrict remote clients to a specific server version, set <code>recursive = false;</code> to make the entire folder read-only. Zed refuses to connect if it cannot provision the required binary, so document the restriction for collaborators.
</translate>


== Tips and tricks ==


            languages = {
==== Vulkan diagnostics ====
                "Elixir" = {
{{code|lang=bash|line=no|1=$ vulkaninfo --summary}}
                    language_servers = ["!lexical" "elixir-ls" "!next-ls"];
<translate>
                    format_on_save = {
<!--T:36-->
                        external = {
Run the command above to check your Vulkan support before launching Zed. Install <code>vulkan-tools</code> if the command is not available. On non-NixOS systems, you may need to wrap Zed with <code>nixGLVulkan</code> from the nixGL package.
                            command = "mix";
</translate>
                            arguments = ["format" "--stdin-filename" "{buffer_path}" "-"];
                        };
                    };
                };
                "HEEX" = {
                    language_servers = ["!lexical" "elixir-ls" "!next-ls"];
                    format_on_save = {
                        external = {
                            command = "mix";
                            arguments = ["format" "--stdin-filename" "{buffer_path}" "-"];
                        };
                    };
                };
            };


            vim_mode = true;
==== Preinstall extensions ====
            ## tell zed to use direnv and direnv can use a flake.nix enviroment.
{{code|lang=json|line=no|1={
            load_direnv = "shell_hook";
  "extensions": [
            base_keymap = "VSCode";
    "nix",
            theme = {
    "toml",
                mode = "system";
    "elixir"
                light = "One Light";
  ]
                dark = "One Dark";
}
            };
}}
            show_whitespaces = "all" ;
<translate>
            ui_font_size = 16;
<!--T:37-->
            buffer_font_size = 16;
Declaratively listing extensions ensures they are installed automatically on new systems while still allowing additional extensions to be added interactively.
</translate>


        };
==== Synchronise settings across machines ====
<translate>
<!--T:38-->
Store the entire <code>~/.config/zed</code> directory in a version-controlled dotfiles repo or manage it with Home Manager to keep settings consistent across hosts.
</translate>
 
== Troubleshooting ==
 
==== Zed fails to start without Vulkan ====
<translate>
<!--T:39-->
If the GUI refuses to launch, confirm that <code>vulkan-tools</code> reports a working ICD. Use <code>nixGL</code> or vendor packages that supply Vulkan drivers for your GPU.
</translate>
 
==== Remote collaboration disconnects ====
<translate>
<!--T:40-->
Ensure the remote server binary matches the client version. Re-run <code>home-manager switch</code> or update the symlink in <code>~/.zed_server</code> if the versions diverge after an update.
</translate>
 
==== Language server missing binaries ====
<translate>
<!--T:41-->
When Zed reports missing tools, add the required executables to <code>programs.zed-editor.extraPackages</code> or wrap the server using <code>pkgs.writeShellApplication</code>.
</translate>


    };
== See also ==
}
* <translate>
<!--T:42-->
[[Home Manager]] – Manage Zed configuration declaratively
</translate>
* <translate>
<!--T:43-->
[[Graphics#Vulkan]] – Set up Vulkan on NixOS systems
</translate>
* <translate>
<!--T:44-->
[https://search.nixos.org/options?query=zed-editor NixOS options search for Zed]
</translate>


</syntaxhighlight>
== References ==
<references/>


[[Category:Applications]]
[[Category:Applications]]
[[Category:Text Editor]]
[[Category:Text Editor]]

Latest revision as of 12:48, 17 October 2025

Zed

Source-code Editor Application

100%
Developer(s)Zed Industries
StatusActive
Operating SystemCross-platform (Linux, macOS, Windows)
Platform(s)Desktop
Language(s)Rust
LicenseAGPL, GPL, Apache License
External links
Websitezed.dev
GitHubzed-industries/zed
Bug trackerGitHub Issues
DocumentationZed Documentation

Zed[1] is a collaborative, GPU-accelerated text editor developed by Zed Industries. It combines fast local editing with real-time multiplayer features and ships with batteries-included tooling for popular programming languages. The editor provides native builds for Linux, including Nixpkgs packages and a reproducible flake. Hardware acceleration requires a GPU with Vulkan support; systems without Vulkan can fall back to emulation via tools such as nixGL.[2]

Installation

Shell

$ nix-shell -p zed-editor

The zed-editor package is available in Nixpkgs from channel 24.11 onward. The command above provides zed-editor in the current shell session without modifying any configuration files.

The package installs both desktop launchers and a CLI entry point aliased to zeditor, mirroring the upstream binary name.

System setup

# In /etc/nixos/configuration.nix
environment.systemPackages = [
  pkgs.zed-editor
];

# In home-manager configuration (home.nix)
home.packages = [
  pkgs.zed-editor
];

Rebuild your system or Home Manager profile to make Zed available persistently. On NixOS, run sudo nixos-rebuild switch; for Home Manager, run home-manager switch.

Flake

Zed maintains an official flake for tracking the latest upstream build. This approach is useful if you need features that have not yet reached stable Nixpkgs.

inputs.zed.url = "github:zed-industries/zed";

outputs = { self, nixpkgs, zed, ... }@inputs: let
  system = "x86_64-linux";
  pkgs = import nixpkgs { inherit system; };
in {
  packages.${system}.zed-latest = zed.packages.${system}.default;
};

Build the flake package with nix build .#zed-latest or expose it in your configuration with the appropriate overlay.

⚠︎
Warning: Zed requires hardware-accelerated Vulkan. On systems without supported drivers, use nixGL or home-manager's nixGL.vulkan.enable = true; to provide the necessary libraries.

Providing Vulkan through nixGL can be more consistent than relying on host distribution packages, especially on non-NixOS systems where Wayland and X11 stacks differ in their Vulkan capabilities.

Configuration

Zed stores its configuration in JSON files under ~/.config/zed. Home Manager can manage these settings declaratively.

Basic

programs.zed-editor = {
  enable = true;
  extensions = [ "nix" "toml" "rust" ];
  userSettings = {
    theme = {
      mode = "system";
      dark = "One Dark";
      light = "One Light";
    };
    hour_format = "hour24";
    vim_mode = true;
  };
};

The configuration above enables Zed via Home Manager, installs a small set of extensions, and synchronises the theme with the desktop appearance.

Advanced

programs.zed-editor = {
  enable = true;

  # This populates the userSettings "auto_install_extensions"
  extensions = [ "nix" "toml" "elixir" "make" ];

  # Everything inside of these brackets are Zed options
  userSettings = {
    assistant = {
      enabled = true;
      version = "2";
      default_open_ai_model = null;

      # Provider options:
      # - zed.dev models (claude-3-5-sonnet-latest) requires GitHub connected
      # - anthropic models (claude-3-5-sonnet-latest, claude-3-haiku-latest, claude-3-opus-latest) requires API_KEY
      # - copilot_chat models (gpt-4o, gpt-4, gpt-3.5-turbo, o1-preview) requires GitHub connected
      default_model = {
        provider = "zed.dev";
        model = "claude-3-5-sonnet-latest";
      };

      # inline_alternatives = [
      #   {
      #     provider = "copilot_chat";
      #     model = "gpt-3.5-turbo";
      #   }
      # ];
    };

    node = {
      path = lib.getExe pkgs.nodejs;
      npm_path = lib.getExe' pkgs.nodejs "npm";
    };

    hour_format = "hour24";
    auto_update = false;

    terminal = {
      alternate_scroll = "off";
      blinking = "off";
      copy_on_select = false;
      dock = "bottom";
      detect_venv = {
        on = {
          directories = [ ".env" "env" ".venv" "venv" ];
          activate_script = "default";
        };
      };
      env = {
        TERM = "alacritty";
      };
      font_family = "FiraCode Nerd Font";
      font_features = null;
      font_size = null;
      line_height = "comfortable";
      option_as_meta = false;
      button = false;
      shell = "system";
      # shell = {
      #   program = "zsh";
      # };
      toolbar = {
        title = true;
      };
      working_directory = "current_project_directory";
    };

    lsp = {
      rust-analyzer = {
        binary = {
          # path = lib.getExe pkgs.rust-analyzer;
          path_lookup = true;
        };
      };

      nix = {
        binary = {
          path_lookup = true;
        };
      };

      elixir-ls = {
        binary = {
          path_lookup = true;
        };
        settings = {
          dialyzerEnabled = true;
        };
      };
    };

    languages = {
      "Elixir" = {
        language_servers = [ "!lexical" "elixir-ls" "!next-ls" ];
        format_on_save = {
          external = {
            command = "mix";
            arguments = [ "format" "--stdin-filename" "{buffer_path}" "-" ];
          };
        };
      };

      "HEEX" = {
        language_servers = [ "!lexical" "elixir-ls" "!next-ls" ];
        format_on_save = {
          external = {
            command = "mix";
            arguments = [ "format" "--stdin-filename" "{buffer_path}" "-" ];
          };
        };
      };
    };

    vim_mode = true;

    # Tell Zed to use direnv and direnv can use a flake.nix environment
    load_direnv = "shell_hook";
    base_keymap = "VSCode";

    theme = {
      mode = "system";
      light = "One Light";
      dark = "One Dark";
    };

    show_whitespaces = "all";
    ui_font_size = 16;
    buffer_font_size = 16;
  };
};

This example adds language servers to the FHS sandbox, enables the bundled assistant, configures the terminal, and ensures remote server binaries are provided declaratively.

The userSettings and userKeyMaps options translate directly into JSON. The extraPackages option includes additional Nixpkgs in the FHS environment, useful for LSP servers (e.g., pkgs.nixd) or optional tools (e.g., pkgs.shellcheck for the Basher LSP).

Home Manager renders settings.json as read-only, which prevents Zed's GUI from saving most preference changes, including AI provider selection. Plan to manage long-term settings declaratively or temporarily disable the module when editing interactively.

Only the initial extension list can be defined declaratively; additional extensions installed through the GUI are stored within Zed's writable data directories and do not appear in userSettings. This follows a similar model to VSCode, where extensions require external binaries downloaded at runtime.

LSP support

Zed downloads language servers into ~/.local/share/zed/languages/, which is read-only on NixOS. Instead, use declarative methods to supply LSP binaries. Check LSP Logs → Server Info to confirm which binaries are running. Prefer language servers packaged in Nixpkgs so that dependencies are resolved within the Nix store.

Nix-ld (recommended)

Enable nix-ld so prebuilt language servers can resolve dynamic libraries without wrapping.

FHS wrapper

Use pkgs.zed-editor.fhsWithPackages to extend the FHS environment with additional system libraries when a language server requires them.

pkgs.zed-editor.fhsWithPackages (pkgs: with pkgs; [ openssl zlib ])

Remember that language servers started inside the wrapper do not automatically inherit tools from ad-hoc shells; include every dependency declaratively.

Bring your own LSP servers

Newer versions of Zed can detect LSP servers installed in PATH and prefer local versions over automatically downloaded ones. Install LSP servers globally or provide them through nix shell. Nixpkgs versions of tools may be required for development on NixOS, especially for the C/C++ ecosystem. Check LSP Logs → Server Info to see which binaries are running. If automatic detection doesn't work, specify the path manually in your Zed configuration:

{
  "lsp": {
    "rust-analyzer": {
      "binary": {
        "path": "/run/current-system/sw/bin/rust-analyzer"
      }
    }
  }
}

Adjust the path for each language server you manage. The example above assumes rust-analyzer is installed in your system profile.

Remote server

Zed uploads a versioned remote server binary to ~/.zed_server on the target host. The Nixpkgs package exposes the matching binary via the remote_server output. When you connect to a remote machine, the client either downloads a matching server binary from upstream or pushes a local copy if "upload_binary_over_ssh": true is enabled. Connections fail if the versions diverge.

home.file.".zed_server" = {
  source = "${pkgs.zed-editor.remote_server}/bin";
  recursive = true;
};

The recursive = true; setting keeps the directory writable while symlinking individual binaries, allowing Zed to add new versions when needed. This is necessary because the ~/.zed_server folder is also used when external clients connect to the current system as a remote. Alternatively, use Home Manager's built-in option for simpler setup:

programs.zed-editor = {
  enable = true;
  installRemoteServer = true;
};

To restrict remote clients to a specific server version, set recursive = false; to make the entire folder read-only. Zed refuses to connect if it cannot provision the required binary, so document the restriction for collaborators.

Tips and tricks

Vulkan diagnostics

$ vulkaninfo --summary

Run the command above to check your Vulkan support before launching Zed. Install vulkan-tools if the command is not available. On non-NixOS systems, you may need to wrap Zed with nixGLVulkan from the nixGL package.

Preinstall extensions

{
  "extensions": [
    "nix",
    "toml",
    "elixir"
  ]
}

Declaratively listing extensions ensures they are installed automatically on new systems while still allowing additional extensions to be added interactively.

Synchronise settings across machines

Store the entire ~/.config/zed directory in a version-controlled dotfiles repo or manage it with Home Manager to keep settings consistent across hosts.

Troubleshooting

Zed fails to start without Vulkan

If the GUI refuses to launch, confirm that vulkan-tools reports a working ICD. Use nixGL or vendor packages that supply Vulkan drivers for your GPU.

Remote collaboration disconnects

Ensure the remote server binary matches the client version. Re-run home-manager switch or update the symlink in ~/.zed_server if the versions diverge after an update.

Language server missing binaries

When Zed reports missing tools, add the required executables to programs.zed-editor.extraPackages or wrap the server using pkgs.writeShellApplication.

See also

References

  1. Zed Industries, "Zed", Official Website, Accessed October 2025. https://zed.dev
  2. Zed Industries, "Linux", Zed Documentation, Accessed October 2025. https://zed.dev/docs/linux