
flowchart TD
A[Start] --> B{Is plugin in nixpkgs?}
B -->|Yes| C[Add to optionalPlugins]
B -->|No| D[Add to flake inputs]
C --> E[Add any plugin dependencies and tools]
D --> E
E --> G[Register to lze in init.lua]
G --> K[Run nix build .]
K --> L[Test with ./result/bin/nvim]
Check it out: nixCats-nvim-example
Run git clone https://github.com/kohane27/nixCats-nvim-example.git ~/.config/nixCats-nvim and start tinkering!
Caveat
My template assumes you are familiar with the Neovim plugin ecosystem, like adding plugins with lazy.nvim in a normal Linux/MacOS environment. This guide only shows you how to do so in Nix/NixOS.
Introduction
I used nixCats-nvim’s example template to get started.
How to Use
git clone https://github.com/kohane27/nixCats-nvim-example.git ~/.config/nixCats-nvim
~/.config/nixCats-nvim/. The directory name has to be called nixCats-nvim.I. Using Nix to download and manage plugins and tools
1. Adding plugins to flake.nix
flake.nix is the entry point for the plugins and tools you want to be managed by Nix. When you want to add any plugins or tools (LSP servers, fzf, stylua etc), this is the file to modify.
Check if the plugin is available in nixpkgs (The naming convention is suffixing -nvim, i.e., if you want to download telescope.nvim search telescope-nvim).
If yes, add it to the optionalPlugins attribute set
If the plugin is not available in nixpkgs, add the following to flake inputs:
"plugins-hlargs" = {
url = "github:m-demare/hlargs.nvim";
flake = false;
};
Note that the name must start with plugins-.
2. Install the plugin’s dependencies
For example, for telescope.nvim, the installation guide for lazy.nvim is below:
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
}
So you need to put plenary-nvim to startupPlugins.
vim-repeat, plenary-nvim, dressing-nvim, nui-nvim, nvim-web-devicons etc are required and shared by many plugins so I don’t bother setting them up in optionalPlugins attribute set.3. Install the plugin’s external dependencies
For example, telescope.nvim requires ripgrep, so we put ripgrep to lspsAndRuntimeDeps.
What if the plugin is not available in Nix and requires a build step?
By build step I mean the following:
{
"nvim-telescope/telescope-fzf-native.nvim",
build = "cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release",
}
Just cry and hope someone step up and contribute it to Nix. jk. You can study how it’s done (ref: avante-nvim) and package it yourself (and hopefully contribute to Nix so that other people can benefit from it).
II. Using lua to configure plugins
1. Import your plugin to lua/custom/plugins/init.lua:
require("lze").load({
{ import = "custom.plugins.telescope" },
})
init.lua. It’ll always be just require("custom").2. Create the plugin init.lua:
With custom.plugins.telescope, create the corresponding lua/custom/plugins/telescope/ and init.lua:
return {
{ "telescope-fzf-native.nvim", dep_of = "telescope.nvim" },
{
"telescope.nvim",
after = function(plugin)
local telescope = require("telescope")
telescope.setup({
extensions = {
fzf = { fuzzy = true },
},
})
telescope.load_extension("fzf")
end,
},
}
2a. Declaring correct names
The name (line 4) is not necessarily the name you expect:
For plugins added via
inputsinflake.nix(i.e., plugins not available in nixpkgs), it’s just the plugin name without-nvim, e.g., ifinputsisplugins-hlargs, the name required ishlargs.For plugins from nixpkgs, it’s usually the plugin name wth
.nvim, e.g., ifpkgs.vimPlugins.toggleterm-nvim, the name istoggleterm.nvim. For nvim-tree.lua, it’s NOTnvim-treeornvim-tree.nvim, it’snvim-tree.lua.
:NixCats pawsible to confirm the required names.2b. Declaring correct dependencies
Continuing our telescope example above. The line { "telescope-fzf-native.nvim", dep_of = "telescope.nvim" } is setting the dependency required by the extension fzf.
{ "telescope-fzf-native.nvim", dep_of = "telescope.nvim" } as “telescope-fzf-native.nvim is dependencies of telescope.nvim”.For example, when you see the following lazy.nvim spec:
{
"yetone/avante.nvim",
dependencies = {
{
"MeanderingProgrammer/render-markdown.nvim",
ft = { "markdown", "Avante" },
},
},
})
The equivalent in lua/custom/plugins/ai/avante/init.lua:
return {
{ "avante.nvim" },
{
"render-markdown.nvim",
dep_of = { "avante.nvim" },
},
}
As you can see, using lze requires you to understand where the plugin comes from and what it needs. It’s more involved than just copying lazy.nvim’s to a new file and have it configure for you.
III. Run nix build
~/.config/nixCats-nvim/.Run nix build "." to build the binary at ./result/bin/nvim Execute and pray there’s no error and your plugin is working.
nix flake update.home-manager Integration
Since I’m using home-manager, I just add it to my path home.sessionPath = [ "$HOME/.config/nixCats-nvim/result/bin" ];
After rebooting:
➜ which nvim
/home/username/.config/nixCats-nvim/result/bin/nvim
Tips
1. Use regularCats to quickly set up and config new plugins
Nobody has the patience to make a small change, run nix build . and wait 20 seconds. regularCats is the perfect use case for it.
The following builds the binary ./bin/regularCats:
nix build ".#regularCats" --out-link regularCats
Once you have made sure the plugin is downloaded and loaded by Nix (:NixCats pawsible), you just make changes to the plugin init.lua and run ./bin/regularCats to see the changes immediately.
I have the following in my home-manager’s aliases.nix:
programs.zsh.shellAliases = {
v = "$(readlink -f ~/.config/nixCats-nvim/result/bin/nvim)";
vv = "$(readlink -f ~/.config/nixCats-nvim/regularCats/bin/regularCats)";
};
flake.nix (add or remove plugins or adding new tools), you still need to run nix build ".".2. Use GitHub search and reference other people’s nixCats-nvim
I used GitHub search when I was setting up mine. I believe my repo is the most complete bloated nixCats-nvim on all of GitHub. But it also serves as an example of how to do various things. Just remove the stuff you don’t need.
3. Debugging
If your plugin is not working:
flake.nix: Move the plugin fromoptionalPluginstostartupPluginsattribute set- set
lazy = falsein your plugininit.lua
For example, when I was setting up typescript-tools-nvim, I realized it did not work if I put it under optionalPlugins. Even adding lazy = false did not work. After a lot of headache, BirdeeHub and I resolved it.