I use lazy.nvim (a.k.a. lazy) for package management as part of the larger LazyVim distribution for Neovim. By default1, lazy checks for updates periodically, and applying all the updates is as simple as pressing uppercase U
in the lazy UI.
This makes it really easy to keep up to date as it lets me follow new innovations in the Neovim ecosystem and try out new ways of doing things. But it has its downsides — namely instability, conflicts and bugs! This may sound tiresome enough to forgo regular updates entirely, but with the right coping and troubleshooting strategies, I’ve figured out how to have my cake and eat it too.
Level 0: Handle a Buggy Plugin
If a plugin has already been pinpointed as the source of the problem, it can be dealt with in a few different ways.
The trivial option: simply uninstall it
If it was installed manually and is no longer wanted, simply uninstall it by removing the relevant spec from lazy config, then restart Neovim.
Tell lazy to disable it
If it came preconfigured with a distribution that uses lazy (e.g. LazyVim) it can’t be removed directly, but it can be disabled. Just define the spec as follows, restart, and lazy will no longer load it:
Rollback and pin it
If it’s still needed, but only an older version works properly, go through the plugin’s commit history and pick a commit that hopefully doesn’t exhibit the problem. Then define the spec as follows:
Open the lazy UI and run an “update” on this plugin by cursoring over the plugin and pressing lowercase u. The plugin will roll back to the specified commit, and will be in its rolled back state after restarting Neovim. If the pinned commit still doesn’t work, repeat the process with an older commit hash until the issue is resolved.
Level 1: Backup and Restore
Lazy maintains a lazy-lock.json
lockfile in the nvim
config directory2, which captures a snapshot of the entire Neovim configured environment at the current point in time. When used properly, this file allows lazy to restore previously working snapshots when a new wave of updates breaks something.
To fully take advantage of this, the nvim
directory — including the lazy-lock.json
file — needs to be committed to a git repository. A commit should be made whenever an update results in a reasonably stable Neovim environment, or before downloading new updates. If git isn’t set up, at least save a backup of the lazy-lock.json
file somewhere safe prior to an update.
If something breaks and it’s not clear which plugin was responsible, discard the changes to the lazy-lock.json
file (or otherwise restore it from a backup location) then simply press R in the lazy UI to restore all plugins back to the versions as defined in lazy-lock.json
. After a Neovim restart, things should be back to the way they were before the update, and now the list of new updates can be reviewed for any troublemakers.
Don't be afraid to commit regularly
Having a regular history of committed snapshots of
lazy-lock.json
greatly helps with walking back in time to find a workable config, even if some of those snapshots were imperfect and somewhat broken.
Level 2: Test a Plugin in Isolation
When it isn’t totally clear where an issue might originate, it can help to try to replicate the issue with a plugin in a minimal environment. This distinguishes plugin bugs (which can be reported to the plugin maintainer) from personal configuration conflicts or mistakes. To do this, create a Lua file as follows:
Then start a Neovim instance with this sole file loaded as its config via nvim -u repro.lua
.
If the issue can be replicated, then the plugin is likely fundamentally broken at its current version. If not, gradually add more configuration options to repro.lua
to trigger the error condition.
If the issue can’t be replicated in this isolated environment, then it likely points to a conflict with another plugin or setting (e.g. keymaps, options, autocmds).
Level 3: Test Against Default LazyVim
To distinguish between personal config issues and those arising from LazyVim’s ecosystem of plugins and settings, use the same repro.lua
file from Level 2: Test a Plugin in Isolation to load in a totally vanilla LazyVim environment with all the default bells and whistles.
When nvim -u repro.lua
is run, it will do a full install3 of all default LazyVim plugins in addition to the suspected troublesome plugin.
If the issue can be replicated at this stage, then it’s likely not an issue with personal configuration settings, and other users of LazyVim may soon chime in with bug reports. At this stage, it could also be fruitful to start disabling certain LazyVim bundled plugins to pinpoint the conflicting area.
If the issue still cannot be replicated, then the blame likely lies within the personal config (i.e. nvim
) folder.
Level 4: Dissect a Personal Config
We go back to a personal config that exhibits some brokenness. What can we do?
I recommend commenting out whole files or sections of config until the problem goes away, which would then indicate the problem area. There’s no quick way to do this, and it relies heavily on intuition.
Assuming it’s a LazyVim config, some areas to consider commenting out:
config/keymaps.lua
config/options.lua
config/autocmds.lua
- the line
{ import = "plugins" }
inconfig/lazy.lua
(disables all custom plugin configs in one fell swoop) - any LazyVim extra modules that were enabled in the same section
- the inside of a spec in any of the files inside
./plugins/
(lets us keep the file and the config code, but will temporarily disable that plugin)
Hopefully one of these will be the difference between a working config and a broken one!
Footnotes
-
For more stability and less temptation to download every single update, this behavior can be turned off by setting
checker { enabled = false }
tofalse
inlazy.lua
↩ -
See
:h standard-path
for where thenvim
config directory lives ↩ -
Don’t worry — the plugins will be installed to a separate
.repro
folder, so it won’t mess up the actualnvim-data
folder where the real instance of Neovim and its plugins run from. ↩