Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

logo

Welcome to the nix4nvchad documentation!

nix4nvchad provides a seamless way to integrate NvChad, a blazing fast Neovim configuration, into your Nix setup.

By leveraging Nix, you can declare your Neovim environment, language servers, and custom configurations deterministically, ensuring your editor setup is identical across all your machines.

Note

This project is designed primarily for use with Nix Flakes. Make sure you have flakes enabled in your Nix installation. See Flakes on the NixOS Wiki for more information.

How it works (Technical Details)

Packaging NvChad for Nix isn’t as straightforward as a standard application package. NvChad is fundamentally a user configuration for Neovim, not a standalone compiled binary.

By default, NvChad lazily loads plugins. On its first launch, it needs to write state files (like lazy-lock.json) and compiled modules to disk. In a standard Linux environment, it writes these to ~/.config/nvim and ~/.local/share/nvim.

However, in Nix, all packages are built and stored in /nix/store, which is strictly read-only. If Neovim tries to run NvChad directly from the Nix store, the editor will crash or throw errors because it cannot write its required runtime files.

The Solution: To bypass this limitation without breaking the deterministic nature of Nix, nix4nvchad uses a wrapper around the nvim executable. When you launch this wrapped nvim:

  1. It checks if the NvChad configuration already exists in your home directory (~/.config/nvim).
  2. If it does not exist, the wrapper automatically copies the immutable NvChad starter files and your custom Nix configurations from the /nix/store into your writable ~/.config/nvim directory.
  3. Finally, it launches Neovim, allowing NvChad to write its lockfiles and state normally while still respecting the dependencies and LSP servers injected via Nix.

Features

  • Home Manager Integration: Easily configure NvChad using our provided Home Manager module.
  • Standalone Package: Use it independently of Home Manager by overriding the Nix derivation directly.
  • Isolated Dependencies: Manage your runtime dependencies (like LSP servers, formatters, and tools) in isolation. They are made available exclusively to NvChad without polluting your global system environment.

Tip

If you are new to NvChad, we recommend reading through the official NvChad documentation to familiarize yourself with its structure and defaults.

Ready to get started? Head over to the Installation guide.

Installation

To install and use nix4nvchad, you must have Nix flakes enabled on your system.

There are two primary ways to integrate nix4nvchad into your setup: using the provided Home Manager module or using the Standalone Package.

Setting up Inputs

First, you need to add the repository to your flake.nix inputs.

You can use the default configuration which automatically pulls the standard NvChad starter repository, or you can override it to use your own fork or local configuration folder.

Default Input:

Note

The default configuration pulls the standard NvChad starter template. This is a minimal, blazing-fast setup. It’s especially useful for servers or lightweight environments where you just want a solid Neovim base without writing custom plugins.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    
    nix4nvchad = {
      url = "github:nix-community/nix4nvchad";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  # ...
}

Input with Custom Starter Repository:

If you have a customized NvChad setup that follows the structure of the starter template, you can override the nvchad-starter input. This tells the flake to build NvChad using your source instead of the default.

Tip

Why do this? Keeping your NvChad configuration in a separate repository using vanilla Lua allows you to use the exact same configuration on systems without Nix. In your Nix configuration, you only need to enable nix4nvchad and pass extraPackages to ensure all LSPs and tools are perfectly wired up. See Advanced Usage for more details.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    
    # Your custom NvChad configuration repository or local folder
    my-nvchad-config = {
      url = "github:YOUR_USERNAME/your-nvchad-repo";
      # Or for a local folder: url = "path:./nvim-config";
      flake = false;
    };

    nix4nvchad = {
      url = "github:nix-community/nix4nvchad";
      inputs.nixpkgs.follows = "nixpkgs";
      inputs.nvchad-starter.follows = "my-nvchad-config"; # Overrides the starter
    };
  };
  # ...
}

Configuring Outputs

Once your inputs are set, you need to make nix4nvchad available in your outputs. You can access the package or module directly by its path, or by passing inputs into your NixOS/Home Manager configuration.

Example 1: Passing inputs to a NixOS Module (with Home Manager):

  outputs = { self, nixpkgs, home-manager, ... }@inputs: 
  let
    system = "x86_64-linux";
  in
  {
    nixosConfigurations.my-system = nixpkgs.lib.nixosSystem {
      inherit system;
      # Makes 'inputs' available in NixOS configuration.nix
      specialArgs = { inherit inputs; }; 
      modules = [
        ./configuration.nix
        home-manager.nixosModules.home-manager {
          # Makes 'inputs' available in Home Manager home.nix
          home-manager.extraSpecialArgs = { inherit inputs; };
          home-manager.users.myuser = import ./home.nix;
        }
      ];
    };
  };

Example 2: Passing inputs for Standalone Home Manager (or nix-darwin):

  outputs = { self, nixpkgs, home-manager, ... }@inputs: 
  let
    system = "aarch64-darwin"; # Or x86_64-linux
    pkgs = import nixpkgs { inherit system; };
  in
  {
    homeConfigurations."myuser" = home-manager.lib.homeManagerConfiguration {
      inherit pkgs;
      # Makes 'inputs' available in home.nix
      extraSpecialArgs = { inherit inputs; };
      modules = [ ./home.nix ];
    };
  };

If you use Home Manager, you can simply import the module.

Warning

Do not install the standard neovim package and nix4nvchad at the same time. nix4nvchad wraps the nvim executable and exposes it to the system. If you enable both the Home Manager programs.neovim module (or install pkgs.neovim globally) and nvchad, it will lead to an executable collision. Even if it installs, whichever nvim binary appears first in your $PATH will take precedence, resulting in undefined behavior and failing plugins.

❌ WRONG:

{ inputs, pkgs, ... }: {
  imports = [ inputs.nix4nvchad.homeManagerModules.default ];

  programs.nvchad.enable = true;
  programs.neovim.enable = true; # Collision!
  home.packages = [ pkgs.neovim ]; # Collision!
}

✅ CORRECT:

{ inputs, pkgs, ... }: {
  imports = [ inputs.nix4nvchad.homeManagerModules.default ];

  programs.nvchad = {
    enable = true;
    # You can configure extra options here (see the Configuration section)
  };
}

Method 2: Standalone Package

If you do not use Home Manager or prefer to handle the package directly, you can access the derivation from the flake outputs.

You can use the package as-is if you rely entirely on a custom starter repository (defined in inputs) or just want the default setup.

{ inputs, pkgs, ... }:
let
  system = pkgs.stdenv.hostPlatform.system;
in
{
  environment.systemPackages = [ inputs.nix4nvchad.packages.${system}.default ];
}

Overriding the Package

If you need to inject Nix packages or configure extra options via Nix, you can use the .override method to customize the package before installing it.

Details on all available override parameters are in the Configuration section.

Local variable definition

{ inputs, pkgs, ... }:
let
  system = pkgs.stdenv.hostPlatform.system;
  nvchad = inputs.nix4nvchad.packages.${system}.default.override {
    # Custom configuration goes here
  };
in
{
  environment.systemPackages = [ nvchad ];
  # Or for Home Manager: home.packages = [ nvchad ];
}

To make your customized NvChad globally accessible as pkgs.nvchad, you can define an overlay.

{ inputs, pkgs, ... }:
let
  system = pkgs.stdenv.hostPlatform.system;
in
{
  nixpkgs.overlays = [
    (final: prev: {
      nvchad = inputs.nix4nvchad.packages.${system}.default.override {
        # Custom configuration goes here
      };
    })
  ];

  # Now you can use it just like any other package from nixpkgs
  environment.systemPackages = [ pkgs.nvchad ];
}

Configuration

Whether you use the Home Manager module or the package override, you can customize your NvChad experience by passing extra configurations, plugins, and packages.

When using Home Manager, these are set under programs.nvchad.<option>. When using the standalone package, they are passed as arguments to the .override { ... } function.

Available Options

Below is a comprehensive list of available options grouped by their purpose.

Note

Options marked with (HM) in their description (enable, hm-activation, backup) are only applicable when using the Home Manager module. They have no effect when using the standalone package .override.


Core & Environment

This section covers options that affect the underlying Neovim executable and the tools available in its environment.

neovim

Type: package
Default: pkgs.neovim

The Neovim package to use under the NvChad wrapper. You can use this to switch to a nightly build or a custom-compiled version of Neovim.

Example (Home Manager):

programs.nvchad.neovim = pkgs.neovim-unwrapped;

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  neovim = pkgs.neovim-unwrapped;
};

extraPackages

Type: list of packages
Default: [ ] (plus default starter dependencies)

A list of additional packages (like LSPs, formatters, linters) to make available to NvChad as runtime dependencies.

Tip

Keep your global environment clean! Add tools like LSPs (e.g., pyright, nil, gopls) here. They will only be available within the NvChad environment, ensuring your editor finds them without polluting your system.

Example (Home Manager):

programs.nvchad.extraPackages = with pkgs; [
  ripgrep
  lua-language-server
  stylua
  nodePackages.bash-language-server
];

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  extraPackages = with pkgs; [
    ripgrep
    lua-language-server
    stylua
    nodePackages.bash-language-server
  ];
};

gcc

Type: package
Default: pkgs.gcc

The GCC compiler you want to use. Tree-sitter relies heavily on a C compiler to build parsers. You can override this if you need a specific compiler toolchain.

Example (Home Manager):

programs.nvchad.gcc = pkgs.gcc13;

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  gcc = pkgs.gcc13;
};

Customization & Plugins

This section covers options for injecting custom Lua code, modifying the UI, and managing plugins.

extraConfig

Type: string
Default: ""

Arbitrary Lua code that will be loaded after NvChad is fully loaded. Use this to set custom vim.opt settings, keymaps, or auto-commands.

Caution

If you have a very complex configuration, writing massive multiline strings in Nix can become hard to maintain. Consider splitting them out into separate .lua files and reading them with builtins.readFile.

Example (Home Manager):

programs.nvchad.extraConfig = ''
  -- Custom vim options
  vim.opt.shiftwidth = 2
  vim.opt.tabstop = 2
  vim.opt.expandtab = true
  
  -- Custom keymaps
  vim.keymap.set("n", "<leader>w", "<cmd>w<CR>", { desc = "Save file" })
'';

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  extraConfig = ''
    -- Custom vim options
    vim.opt.shiftwidth = 2
    vim.opt.tabstop = 2
    vim.opt.expandtab = true
    
    -- Custom keymaps
    vim.keymap.set("n", "<leader>w", "<cmd>w<CR>", { desc = "Save file" })
  '';
};

chadrcConfig

Type: string
Default: ""

Configuration that replaces chadrc.lua. This is primarily used to override the default UI configuration (themes, transparency, etc.).

Important

Make sure to include local M = {} at the top, and return M at the bottom of your string.

Example (Home Manager):

programs.nvchad.chadrcConfig = ''
  local M = {}
  M.ui = {
    theme = "catppuccin",
    transparency = true,
  }
  return M
'';

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  chadrcConfig = ''
    local M = {}
    M.ui = {
      theme = "catppuccin",
      transparency = true,
    }
    return M
  '';
};

extraPlugins

Type: string (Lua code)
Default: ""

A string containing a Lua table of extra plugins you want to install. This list will be loaded and managed by lazy.nvim.

Example (Home Manager):

programs.nvchad.extraPlugins = ''
  return {
    { "equalsraf/neovim-gui-shim", lazy = false },
    { "nvim-lua/plenary.nvim" },
    {
      "xeluxee/competitest.nvim",
      dependencies = "MunifTanjim/nui.nvim",
      config = function() require("competitest").setup() end,
    },
  }
'';

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  extraPlugins = ''
    return {
      { "equalsraf/neovim-gui-shim", lazy = false },
      { "nvim-lua/plenary.nvim" },
      {
        "xeluxee/competitest.nvim",
        dependencies = "MunifTanjim/nui.nvim",
        config = function() require("competitest").setup() end,
      },
    }
  '';
};

lazy-lock

Type: string (JSON content)
Default: ""

The contents of a lazy-lock.json file. If provided, this will lock lazy.nvim’s plugin versions to ensure reproducible plugin installations. Leave it empty if you want lazy.nvim to manage the lockfile dynamically in your home directory.

Example (Home Manager):

programs.nvchad.lazy-lock = builtins.readFile ./lazy-lock.json;

Example (Standalone):

nvchad = inputs.nix4nvchad.packages.${system}.default.override {
  lazy-lock = builtins.readFile ./lazy-lock.json;
};

Home Manager Specifics

These options dictate how the Home Manager module behaves when activating the configuration.

enable

Type: boolean
Default: false

(HM) Enables the NvChad Home Manager module. If set to false, the module is ignored when building the new generation.

Example:

programs.nvchad.enable = true;

hm-activation

Type: boolean
Default: true

(HM) If set to false, Home Manager will not automatically copy the NvChad configuration to ~/.config/nvim. This allows you to manage the configuration directory manually (e.g., by cloning the NvChad repository yourself) while still using the wrapped executable and isolated dependencies provided by this module.

Example:

programs.nvchad.hm-activation = false;

backup

Type: boolean
Default: true

(HM) Because this module copies NvChad to ~/.config/nvim instead of creating a read-only symlink (a necessary workaround for NvChad’s lazy-loading), it will create a backup of your existing configuration at ~/.config/nvim_%Y_%m_%d_%H_%M_%S.bak during generation switches.

If you do not want backups to be created, disable this option.

Example:

programs.nvchad.backup = false;

Advanced Usage

Overriding the Starter Repository

By default, nix4nvchad pulls the NvChad starter template to initialize the configuration. This provides a minimal, fast setup out-of-the-box.

Important

If you have your own fork of the starter repository or a completely customized NvChad structure, you can override the source used to build the derivation. Your repository or local folder must follow the structure of the official NvChad starter.

Benefits of a Custom Starter:

  1. Portability: You can maintain your Neovim configuration in pure, vanilla Lua. This means you can clone and use your configuration on any machine or distribution, even if it doesn’t have Nix installed.
  2. Minimal Nix Config: Your Nix configuration remains incredibly clean. You only need to declare nix4nvchad and populate extraPackages to guarantee that Neovim can find the executables for your LSPs, formatters, and linters.

Defining the Custom Source

You can override the source by defining it in your flake.nix inputs. This can be a GitHub repository or a local path on your machine.

Example (GitHub Repository):

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    
    # Your custom NvChad configuration repository
    my-nvchad-config = {
      url = "github:YOUR_USERNAME/my-nvchad-config";
      flake = false;
    };

    nix4nvchad = {
      url = "github:nix-community/nix4nvchad";
      inputs.nixpkgs.follows = "nixpkgs";
      inputs.nvchad-starter.follows = "my-nvchad-config"; # Overrides the starter
    };
  };
  # ...
}

Example (Local Folder): If you manage your dotfiles in a single repository and want to point to a local nvim folder:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    
    # Path to your local nvim configuration folder
    my-nvchad-config = {
      url = "path:./path/to/your/nvim/folder";
      flake = false;
    };

    nix4nvchad = {
      url = "github:nix-community/nix4nvchad";
      inputs.nixpkgs.follows = "nixpkgs";
      inputs.nvchad-starter.follows = "my-nvchad-config"; # Overrides the starter
    };
  };
  # ...
}

Once the input is overridden, nix4nvchad will automatically use your custom Lua files to build the wrapped Neovim derivation.

Deprecated Features

This page lists features, attributes, or configuration options that are currently deprecated and slated for removal in future versions of nix4nvchad.

homeManagerModule Attribute

The flake output attribute inputs.nix4nvchad.homeManagerModule is deprecated and will be removed in the near future.

Why is it being removed?

In the Nix flake ecosystem, Home Manager modules exported by a flake are inherently non-standard (unlike NixOS or nix-darwin modules). The standard and most widely accepted way to export these is under the homeManagerModules (plural) attribute, typically exposing the default module as homeManagerModules.default.

Maintaining the singular homeManagerModule attribute is redundant, creates unnecessary aliases in the flake output, and can trigger validation warnings in some Nix checking tools.

What should you use instead?

You should update your imports to use the standard homeManagerModules.default path.

❌ Deprecated:

{ inputs, pkgs, ... }: {
  imports = [
    inputs.nix4nvchad.homeManagerModule
  ];
  
  programs.nvchad.enable = true;
}

✅ Recommended:

{ inputs, pkgs, ... }: {
  imports = [
    inputs.nix4nvchad.homeManagerModules.default
  ];
  
  programs.nvchad.enable = true;
}