Using luasnip with nixvim and home manager

I’m configuring my system with NixOS for the first time, and struggling a bit to set up my nixvim config correctly. I’m using flakes for my system config and Home manager. I’m also using the 23.11 sources for the system pkgs, home manager and nixvim.

The problem I’m having is specifically with the luasnip nvim plugin, which I’m trying to use along with cmp. Enabling luasnip via the nixvim exposed option or adding it to the extra packages and manually intializing it with lua config both fail to make luasnip available to be called in my cmp keybind. I’ve inspected the produced init.lua file to verify that both approaches do in fact reference luasnip with require("luasnip"), however running the defined function throws the following error: attempt to index global 'luasnip' (a nil value).

I have limited experience with nvim, lua and nix, but similar configs on github seem successful just by enabling luasnip through the nixvim option and calling it in the same fashion as I do. What am I missing here?

My nixvim config:

 { inputs, pkgs, ... }: {

   imports = [
     inputs.nixvim.homeManagerModules.nixvim
   ];
   programs.nixvim = {
     enable = true;

     colorschemes.tokyonight.enable = true;

     options = {
       relativenumber = true;
       shiftwidth = 2;
     };

     extraConfigLua = ''
       require("luasnip").setup({})
       '';

     # Set leader key to space
     globals.mapleader = " ";

     ############### Plugins ###############
     plugins = {

       # Language service providers
       lsp = {
         enable = true;
         servers = {
           # Nix
           nil_ls.enable = true;
         };
       };

       # Handy code snippets
       # luasnip.enable = true;

       # Completion engine
       cmp_luasnip.enable = true;
       cmp-nvim-lsp.enable = true;

       nvim-cmp = {
         enable = true;
         autoEnableSources = true;
         # snippet.expand = "luasnip";
         sources = [
           {name = "nvim_lsp";}
           {name = "path";}
           {name = "buffer";}
           {name = "luasnip";}
         ];

         mapping = {
           "<CR>" = "cmp.mapping.confirm({ select = true })";
           "<Tab>" = {
             action = ''
               function(fallback)
                 if cmp.visible() then
                   cmp.select_next_item()
                 elseif luasnip.expandable() then
                   luasnip.expand()
                 elseif luasnip.expand_or_jumpable() then
                   luasnip.expand_or_jump()
                 else
                   fallback()
                 end
               end
             '';
             modes = [ "i" "s" ];
           };
         };
       };
     };

     # Plugins that aren't exposed through nixvim
     extraPlugins = builtins.attrValues {
     inherit (pkgs.vimPlugins)

       luasnip;
     };
   };
 }

After some time trying lots of different approaches, I managed to make it work. I’m still confused why it didn’t work originally, as it seems to work for others, and I don’t know which of these changes actually made the difference, but I’ll put it here in case someone else encounters the same issue.

  1. To avoid the nil reference error I first created a local binding in the cmp keymap lua function where the message originated. As this mitigated the runtime error I’m guessing that luasnip was correctly referenced at this point, but still no snippets…
          "<Tab>" = {
            action = ''
              function(fallback)
                local luasnip = require('luasnip')
                if cmp.visible() then
                  cmp.select_next_item()
                elseif luasnip.expandable() then
                  luasnip.expand()
                elseif luasnip.expand_or_jumpable() then
                  luasnip.expand_or_jump()
                else
                  fallback()
                end
              end
            '';
            modes = [ "i" "s" ];
  1. Unrelated to luasnip, but correcting a mistake in the config, I made sure to enable the plugins whose cmp sources I was listing:
      # Completion engine
      cmp-nvim-lsp.enable = true;
      cmp-path.enable = true;
      cmp-buffer.enable = true;
      cmp_luasnip.enable = true;

      nvim-cmp = {
        enable = true;
        autoEnableSources = true;
        sources = [
          {name = "nvim_lsp";}
          {name = "path";}
          {name = "buffer";}
          {name = "luasnip";}
        ];
...
  1. Finally, I also enabled friendly-snippets and configured luasnip to load these. After this change, the snippet engine seems to work as intended!
    # Isn't exposed through nixvim, need to add as an extraPlugin.
    # Although friendly-snippets is listed in the documentation, the
    # option is not available to me. I'm guessing it is available using
    # unstable instead of 23.11
    extraPlugins = builtins.attrValues {
      inherit (pkgs.vimPlugins)
        friendly-snippets; # Snippets for luasnip
    };

… and to configure luasnip to use it:

      luasnip = {
        enable = true;
        fromVscode = [
          {}
        ];
      };