Neovim - can't load plugins


I’m using Nix + home-manager on an arch system. I recently converted my neovim install to nix and started to migrate some of the packages to nix from lazy.nvim

I’m noticing, while my regular lua config loads fine, plugins added via nix can not be found.

Here is the relevant nix file:

my home-manager state version is 22.11

I’ve been racking my brain trying to find out why this doesn’t work.

The neovim bin file looks to have the proper commands to load the plugins, but when I check my runtimepath and packpath, they don’t included `/nix/store/skdjf…sdfs-vim-pack-dir" directories.

I have a theory that maybe the commands are being ignored?
Or maybe because I have config loaded, plugins defined in nix are ignored?

tree-sitter binary seems to work. And checkhealth doesn’t report anything funny.

I appreciate any help or direction.

Ok, I tried another approach

final: prev:
  neovim = prev.neovim.overrideAttrs (oldAttrs:
      nixpackdir = prev.pkgs.writeText "nixpackdir" ''
        set packpath^=${prev.vimUtils.packDir oldAttrs.passthrough.packpathDirs}
        set rtp^=${prev.vimUtils.packDir oldAttrs.passthrough.packpathDirs}
      postInstall = oldAttrs.postInstall + ''
        ln -s ${nixpackdir} $HOME/.config/nvim/nixpackdir.vim

Although this builds, this seems to have no effect. I’m not sure if it’s not running or just erroring during the build step?

It’s probably not running, you can’t create a file in /var/empty/.config/nvim/nixpackdir.vim. Nix builds are sandboxed, you can’t do side-effectful things like that.

Why is it not running? I think you’re applying the overlay wrong for flake-parts, but I have no idea how flake-parts applies overlays, never saw the point of using these utility libraries, they just obfuscate the NixOS module system. You also need to make sure to apply the overlay to your home-manager nixpkgs, not your NixOS one.

I would also strongly suggest using the option to apply overlays, instead of trying to change _module.args: Appendix A. Configuration Options

Or just do the overrideAttrs in programs.neovim.package, no reason to create an overlay for a small change to a leaf application like this.

This is irrelevant, by the way. That number is there for your configuration to know what version your stateful on-disk leftovers were created at (neovim seems to have none), so that it can apply the correct backwards-compatibility workarounds. Don’t change this number, but it’s also rarely useful to tell anyone what it is.

It would be more useful to know your home-manager commit, in case this is an upstream bug, but I don’t think it is in this case and that version is visible in your flake.lock anyway.

I’m sadly less familiar with neovim configuration, so can’t tell at a glance what’s wrong either. It seems home-manager uses this function to create the wrapping configuration:

This means your vim “binary” should be a little wrapper script that sets a bunch of environment variables instead. From your symptoms I’m guessing this wrapper isn’t running. Any chance you’re accidentally installing a second clean copy of vim/neovim somewhere that overrides this wrapper since it appears earlier in $PATH?

1 Like

Thanks, good to know!

I did it as an overlay to get access to vimUtils. I wasn’t sure I could get access to it otherwise.

Is it not allowed from an overlay? How would I otherwise? I know I can spit out files from home-manager.

I’m not using NixOs, it’s just home-manager. I’m on Arch Linux.

Yes, I can verify this is correct, my ~/.nix-profile/bin/neovim does set the proper PATH variable and adds the --cmd to set rtp/packpath in neovim on call.

I’m pretty sure I’m not calling an unwrapped or secondary install of neovim. which nvim points to the wrapper script.


But even if I call the wrapped script directly I don’t see the proper rtp/packpath set. It feels like the commands passed to neovim are being ignored. I wasn’t able to find a way to print out what arguments neovim was called with, something similar to a bash scripts ability to see $@.

Here is the relevant line in the script

exec -a "$0" "/nix/store/m8walnvbazdfl0aza26j614xx734rsvg-neovim-unwrapped-0.9.1/bin/nvim"  --cmd "lua vim.g.loaded_node_provider=0;vim.g.loaded_perl_provider=0;vim.g.loaded_python_provider=0;vim.g.python3_host_prog='/nix/store/m95fwym025zfk0yydk6ngx5yvyq3gdr0-neovim-0.9.1/bin/nvim-python3';vim.g.ruby_host_prog='/nix/store/m95fwym025zfk0yydk6ngx5yvyq3gdr0-neovim-0.9.1/bin/nvim-ruby'" --cmd "set packpath^=/nix/store/zk7np1n80sqvbgc05w0lbj57yb95789a-vim-pack-dir" --cmd "set rtp^=/nix/store/zk7np1n80sqvbgc05w0lbj57yb95789a-vim-pack-dir" "$@" 


It seems like I need to utilize home-manager to output symlinks:

But I don’t know how to access packdir and packdirPaths in that scope.
Is there a way to find the nixpackdir output in the store and use mkOutOfStoreSymLink to link it to the write place?

It’s not that it is forbidden from within an overlay, it’s forbidden from within any package build. What your overlay does is change the neovim package in your instance of nixpkgs to be the package you write. The package you write is the result of taking the neovim package build instructions, and changing its postInstall command.

This will make nix build a new neovim, and run your postInstall command instead of the one from the original package.

“install” commands in nix land are not really installing anything onto the actual system, unlike for other distro’s packages (in case you’ve touched pkgbuilds before). They are supposed to place files in /nix/store, you use the $out variable to refer to the output directory of the build. Any attempt to write to anywhere except the $out path will usually fail with read-only errors because the build sandbox prohibits this.

It’s called “install” mostly for historical reasons I guess, and because the abstraction is kind of similar.

So if you want to write to the system, you need to do something else…

home-manager is a very different beast. It also uses nix behind the scenes, but only to evaluate the configuration language and build packages.

Your home-manager configuration is condensed into a big ol’ bash script, called the “activation” script. When you run home-manager switch, it goes and tells nix to build a package that depends on all the packages you added to home.packages and such, and that package just contains this “activation” script that when you run it will create a whole bunch of symlinks to /nix/store in your home-directory.

So when you spit files out of home-manager, you don’t really use nix to do so. You run a script called home-manager which uses nix to build a different script, which it then executes to spit out all these files.

Hence, you can’t create files outside /nix/store in the actual nix code.

Gotcha, my bad!

You can just use pkgs.vimUtils. prev as an overlay argument is exactly the same as pkgs, but after any previous overlays in your overlay list were executed.

Yep, you don’t need to do anything that complex though. You can just use the home.file option.

The passthru attribute of a package build ends up in the final package as well. If passthrough is a kind of typo, I think you should be able to access those with pkgs.neovim.packpathDirs.

That said… This strikes me as a severe hack. This should just work out of the box. Maybe ask on matrix or IRC before going to these lengths?

1 Like

Plot twist

I opened neovim with nvim -u NONE to ignore all plugins/rc files and you know what? rtp and packpath where added correctly.

Some more digging shows that rtp is correct on first load but is being overwritten at some point afterwards.

It’s strange though, since nix neovim runtime is still there.

I’d say it’s save to say that this is not a nix issue.

On another note, I was able to use your advice and leverage home-manager to spit out a lua file with the correct runtime paths. I could use this to circumvent the issue, but I could just as well save the rtp before paths are loaded, then readd them afterwards. At least until I can figure out what is overwriting ftp.

Thanks for the help!


Found the issue. This is a very surprising feature of Lazy.nvim, which is to wipe away runtimepaths and packpaths while assuming control of the entire startup sequence. Luckily I can disable this feature.

1 Like

lazy wants to control everything while nix installs plugins directly in packpath or add a folder with plugins to rtp so these config knobs are needed with nix

require('lazy').setup('lazyplugins', {
	performance = {
		-- we install some packages via nix so we want to load from packpath too
		reset_packpath = false,
		-- rtp = { reset = false, } can be used too