Open-source project
oxalica/nil avatar
oxalica/nil

nil Nix Language Server Setup and Integration

NIx Language server, an incremental analysis assistant for writing in Nix.

1,924 stars73 forksRustApache-2.0

At a glance

What is it?
nil is a Rust-based Language Server Protocol implementation for Nix code, with editor integrations for Neovim, Emacs, VSCode, Vim, Kate, and Eglot. It suits Nix users who want language-aware assistance, subject to its known Neovim semantic highlighting performance issue.
Who is it for?
Adopt nil if your team edits Nix files in an editor with Language Server Protocol support and wants a dedicated Nix analysis assistant without building the server from source. Do not adopt it if your workflow requires documented rollback, a complete feature specification, or a Neovim environment unaffected by the known semantic highlighting problem.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 90 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What nil adds to a Nix editing workflow

nil addresses the basic problem that a generic text editor does not understand the structure and evaluation context of a Nix expression. It is an incremental analysis assistant for writing Nix, implemented in Rust and exposed through the Language Server Protocol. The intended users are Nix and NixOS developers who edit `.nix` files, `flake.nix`, and Nix-related configuration through an LSP-capable editor.

The project is not a Nix package manager, evaluator, formatter, or build system. Its role is editor assistance. The README connects nil to the `nil` package in nixpkgs and to the topics associated with Nix, NixOS, and nixpkgs, while its configuration documentation is explicitly identified as the place for all tunable options. The README does not provide a complete feature inventory. It points to `docs/features.md`, but labels that document as an incomplete list of notable features currently implemented or planned. That distinction matters during adoption because the main page does not establish that every planned capability is available.

A formatter such as `nixfmt` is also a separate concern in the documented editor examples. Those examples expose formatting as an external command, which indicates that nil should not be evaluated as a replacement for formatting or package management. Its central value is narrower: acting as the Nix-aware server behind editor integrations.

The Rust workspace behind nil

The repository layout exposes a Rust workspace rather than a single undifferentiated binary. `Cargo.toml` names six members: `crates/builtin`, `crates/ide`, `crates/nil`, `crates/nix-interop`, `crates/ssr`, and `crates/syntax`. It would be inaccurate to assign more detailed responsibilities without consulting their source.

The public process is still the standard LSP arrangement shown in the editor examples. An editor starts the executable named `nil`, associates it with the `nix` filetype, and then exchanges language-server requests for that buffer. Some integrations define `flake.nix` as a root pattern. Opening a Nix file therefore initiates an editor-managed session in which nil can inspect the document and return applicable language-server results.

The project description calls nil an incremental analysis assistant, but the README does not explain its cache invalidation, dependency graph, evaluation strategy, or project discovery algorithm. It also does not document memory usage, latency, or behavior on very large Nix expressions. Developers evaluating nil for large repositories should treat those internal performance characteristics as undocumented rather than assuming that the word incremental establishes a particular architecture.

Installing nil through nixpkgs or its flake

The shortest documented installation path uses Nix package management. This avoids compilation and leaves Rust and Nix build prerequisites to the existing Nix installation. The following command installs the `nil` attribute from nixpkgs through `nix-env`.

bash
nix-env -iA nixpkgs.nil

For newer profile-based Nix usage, the README provides this command instead.

bash
nix profile install nixpkgs#nil

After either installation, `nil` needs to be on the editor process's `PATH`. The Emacs Eglot example makes this requirement explicit in its comment: "Ensure `nil` is in your `PATH`." A shell installation can succeed while an editor launched through a desktop session or another environment still fails to find the binary.

The repository also publishes a default flake output. Installing that output uses this command.

bash
nix profile install github:oxalica/nil

The package is exposed under `bin/nil` in the repository flake. This path is useful when the project is added as a flake input to a system-wide or home configuration. The README warns that overriding flake inputs with `follows` can prevent a build because those substitutions are not guaranteed to work. The checked-in `flake.lock` is the combination documented as tested in CI.

Source installation requires stable Rust 1.89 or newer, Nix 2.4 or newer, and `nix` available in `PATH`. The documented Cargo command is below.

bash
cargo install --git https://github.com/oxalica/nil nil

This path adds compiler and source-build maintenance to the installation. For routine adoption, the nixpkgs package or repository flake is the clearer choice.

Connecting nil to a real editor session

A first useful setup should connect the installed executable to an editor and open an actual Nix project. The repository provides official support through `nvim-lspconfig`, while coc.nvim, vim-lsp, lsp-mode, lsp-bridge, Eglot, Nix IDE, and Kate LSP Client each have documented registration examples. The examples consistently associate `nil` with Nix files. Several also use `flake.nix` as a project-root signal, which is important for editor features that depend on finding the surrounding project.

For coc.nvim, open its settings with `:CocConfig`, then add the `nil` command under the `nix` language entry. This is the README's first concrete registration example. It also shows how an external formatter command can be placed in nil's settings without changing the server command itself. The example permits reader-specific tuning of the server settings, but `docs/configuration.md` remains the authoritative list of tunable options.

For VSCode or VSCodium, the Nix IDE extension can enable the language server and point it at the executable with `nix.enableLanguageServer` and `nix.serverPath`. For Neovim, the README points to upstream `nvim-lspconfig` documentation and provides `dev/nvim-lsp.nix` as an example configuration for testing. For Vim, `vim-lsp` registers the server only when the `nil` executable is present. For Emacs, both `lsp-mode` and `lsp-bridge` examples explicitly select nil, while the Eglot example attaches it to `nix-mode`.

The concrete first-use check is to open a `.nix` file in a project containing `flake.nix` and confirm that the editor starts `nil`. The README does not specify a command that prints diagnostics or forces a manual analysis, so there is no documented CLI tutorial for exercising every feature after installation.

Neovim highlighting and other adoption constraints

The clearest limitation is documented under the Neovim integration. The README reports a known performance issue with semantic highlighting when nil is used through Neovim's native LSP support and links to `https://github.com/oxalica/nil/issues/83` for details. The page does not quantify the problem or identify affected versions, so an adopter should reproduce the issue with the intended Neovim and nil versions before making it a default.

Feature coverage is another constraint. The README links to `docs/features.md`, but explicitly calls that list incomplete and mixes notable features that are implemented or planned. Nil should therefore not be chosen on the assumption that every Nix language feature is already supported.

The README also does not document a rollback procedure for editor integrations, configuration migration between releases, or behavior when several nil versions are installed. Its release notes are the documented source for changelog information between releases. The repository layout includes dedicated `dev` configurations for several editors, which gives adopters concrete references, but it does not replace a release-specific upgrade check.

Finally, an LSP server only helps if the selected editor can launch the executable and connect to the buffer correctly. Environment differences in `PATH`, root detection, or client configuration can look like server failure even when installation succeeded. The Eglot example's explicit `PATH` warning and the coc.nvim root pattern are therefore operational details, not optional trivia.

License, releases, and upgrade work

nil is distributed under a dual-license arrangement. The repository root contains both `LICENSE-APACHE` and `LICENSE-MIT`, while `Cargo.toml` records `MIT OR Apache-2.0`. The README likewise says that nil is primarily distributed under both terms. This is a licensing choice to review in source distributions and organizational policy, but this article does not provide legal interpretation.

The repository is not archived. Its last push was on 2026-07-26. Snapshot releases are listed for 2026-07-23, 2025-06-13, and 2024-08-06. The README points users to the GitHub releases page for changes between releases. It does not publish a semantic-version compatibility promise, because the workspace version shown in `Cargo.toml` is `0.0.0` and the release entries are snapshot releases.

Installation method affects upgrade effort. A nixpkgs installation can move when the nixpkgs channel or lock input changes. A repository flake install is tied to the repository output selected by the user's profile or flake input. A Cargo source installation leaves the adopter responsible for rebuilding with the documented stable Rust 1.89 requirement or newer. Editor packages also add an upgrade layer because `nvim-lspconfig`, coc.nvim, Nix IDE, Emacs clients, and Vim plugins can change independently of nil.

No release cadence beyond the listed snapshots and push activity is guaranteed by the README. The recent releases are useful upgrade checkpoints, but the documented release notes remain the proper source for deciding whether a change affects a deployed editor configuration.

Why a formatter or general-purpose Nix tool differs

A real alternative is a general-purpose Nix CLI or an editor-only Nix syntax tool, but it solves a different problem. Commands associated with Nix evaluate expressions, build packages, manage profiles, or inspect Nix data. They do not provide the documented LSP editor registration flow implemented by nil.

The examples also show `nixfmt` configured as an external formatting command. That division is concrete: nil is the language server, while `nixfmt` is invoked separately when the user configures formatting. A toolchain that only evaluates or formats Nix can still lack editor diagnostics and LSP sessions, while nil alone is not a substitute for package management or evaluation.

Another alternative is using a general LSP client without a dedicated Nix server. That can connect to an editor's language infrastructure, but it does not turn an unspecified protocol server into a Nix-aware one. The relevant question is not whether an editor supports LSP in general. It is whether that editor can start the `nil` executable, recognize Nix buffers, and expose the project root and nil-specific settings used by the selected integration.

Editorial conclusion

Adopt nil if your team edits Nix files in an editor with Language Server Protocol support and wants a dedicated Nix analysis assistant without building the server from source. Do not adopt it if your workflow requires documented rollback, a complete feature specification, or a Neovim environment unaffected by the known semantic highlighting problem. Before standardizing it, verify that your chosen editor configuration launches `nil` successfully, recognizes `flake.nix` as the project root, and starts the server from a Nix buffer. The adoption judgement turns on those three checks because the repository documents multiple integrations but leaves its notable feature list incomplete.

Frequently asked questions

How do I install nil for Nix development?

The README offers `nix-env -iA nixpkgs.nil`, `nix profile install nixpkgs#nil`, and `nix profile install github:oxalica/nil`. Source installation requires stable Rust 1.89 or newer, Nix 2.4 or newer, and `nix` on `PATH`.

Which editors can use nil?

The README documents configurations for Neovim with `nvim-lspconfig`, Vim and Neovim with coc.nvim, Vim with `vim-lsp`, Emacs with `lsp-mode`, `lsp-bridge`, and Eglot, VSCode or VSCodium with Nix IDE, and Kate with LSP Client Plugin.

Does nil support Neovim semantic highlighting?

The README includes a Neovim semantic highlighting configuration, but it also records a known performance issue in native LSP highlighting and links to issue 83 for details. The documentation does not quantify its severity.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. oxalica/nil on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/oxalica-nil.svg)](https://hysenlabs.com/projects/oxalica-nil)

Was this useful?