Trying out lazy.nvim

2024-06-05

During the few months, following the news that packer.nvim is deprecated, I wanted to try out the new cool package manager in town lazy.nvim. I spent a bit of time migrating over my personal and work configurations over to lazy. Here are some thoughts I had during the migration.

To give a bit of context, my journey on /n?vim/ package managers is the following:

  1. Vim no package manager
  2. Vim + vim-plug
  3. Neovim + vim-plug (VimL)
  4. Neovim + packer.nvim (Lua)
  5. Neovim + Lazy.nvim (Lua)

The good

On the good part and as a first impression, lazy.nvim setup and installation is pretty simple, just copy the lines of the self-bootstrap code, restart nvim and it downloads and install lazy flawlessly. In case you have any issue :checkhealth lazy has good self-check that provides insightful debugging information. This is definitively on par with packer.nvim and from memory even working better than vim-plug.

Perhaps the best tool lazy.nvim provides is its UI. It is very practical, information dense and is very easy to navigate. Launch :Lazy and just follow the UI shortcuts to jump around between which lazy-loaded plugins are launched. Which ones are not loaded yet and what shortcut or event will launch them. The profiler is a great tool to understand which plugin has a strong impact on startup-time, and decide which plugins are worth spending time configure to lazy load.

Also, the pining of dependencies version is a game-changer, copying from modern package managers, it helps a lot with sharing a configuration across multiple machines. Pining plus headless nvim, allows updating the packages in one command line, even in a CI environment.

The medium

Lazy.nvim taking a radically different approach on configuration of plugins than other more common plugin managers, it requires a mental shift in how to configure each plugin. Other package managers (such as plug or packer) typically have one location where the plugins are declared, and another one where they are configured, those package managers leverage vim plugin infrastructure which is quite standard and common nowadays.

It results in configurations that look like such:

-- 1. Declare loaded plugins
require('packer').startup(function(use)
   use "mbbill/undotree"
end)

-- 2. Configure each plugin using plugin README:
vim.keymap.set("n", "<leader><u>", vim.cmd.UndotreeToggle, {
    desc = "Show nvim undotree",
})

Those configuration, being standard by other plugin manager are easy to copy, edit and understand just following each plugin README.

Lazy goes another route where it needs specific syntax to install and configure a plugin. This is a requirement for lazy loading. This allows lazy-nvim to hook on specific events and keymaps to launch a plugin.

The same package, configured under lazy.nvim will more look like this:

require("lazy.nvim").setup({
  {
    "mbbill/undotree",
    lazy = true,
    keys = {
      { "<leader>u", function() vim.cmd.UndotreeToggle() end,
        desc = "Show nvim undotree",
      },
      config = true,
    },
  }
})

Notice the specific syntax to setup new keybindings, it allows lazy-nvim to bind those keys to the loading of the plugin, thus supporting lazy loading.

It highlights a couple of struggles I had with lazy-nvim:

  1. Documentation is sparse while requiring a mental model shift
  2. This syntax being non-standard does result in a ecosystem split

At least while I become familiar with lazy-nvim, this causes some difficulties when configuring unknown plugins where I need to understanding the specifics of a plugin and them map this to the proper lazy-nvim syntax. This is similar to the layered configuration issue Nix packages have.

Similarly, during first setup it was not very clear from the documentation the difference between init, config, setup, opts & main. I should probably open a pull request to add some concrete examples, this would help the understanding.

Conclusion

I am keeping Lazy-nvim for now, it is a great package manager. I am a bit afraid of the day I'll need to move out of it, given it's configuration lock-in. I haven't tested the auto-reload feature which seems very interesting.

You can see my nvim configuration at: dimtion/dotfiles