Leveraging lazy.nvim Structural Features after Migrating from Packer
How I made my Neovim config faster and more extensible
Leveraging lazy.nvim Structural Features after Migrating from Packer
I realized I was doing lazy loading wrong and needed to finish my migration from Packer to lazy.nvim. Here’s how I leveraged the lazy.nvim structural features to get a nicer Neovim configuration.
Several months ago I migrated from using Packer as my package manager in Neovim to using lazy.nvim. Not only because Packer was unmaintained but because I wanted a better experience.
I love all the bells and whistles lazy.nvim provides and I have grown to appreciate the lazy loading and many other features that are available.
After working on and publishing the Obsidian / Neovim video, I saw this comment about lazy loading:
In the video I added the obsidian configuration into the after/plugins directory that gets loaded at the very end of the lifecycle.
Here’s a great video talking about the different runtime directories and how they get loaded:
It had been on my list to revisit my configuration and try and remove the after/plugin directory. If I migrated to using a different pattern then I could take advantage of the lazy loading and other features of lazy.nvim.
What I found was that I could place my lua table of plugins into a file called plugins.lua
and then add individual plugins files into lua/plugins
and lazy.nvim would merge all of them together.
The Migration
I wanted to move files around in a way that did not break my configuration entirely in the process.
First, I created the plugins.lua
file under ~/.config/nvim/lua/
and put in a placeholder empty table.
return {}
Next, I grabbed all my plugins from the local plugins
variable I had in lazy.lua and moved those into the plugins.lua file table. When I did this I updated the lazy setup command to use the “plugins” string.
require("lazy").setup("plugins", {
change_detection = {
notify = false,
},
})
At this point I wanted to double check everything was still working so I restarted Neovim and everything was still in a working state.
Now we could tackle each of the files underneath the after/plugins
directory. Each of these files only had keymaps or config related to a plugin. For lazy.nvim to be able to merge our plugin files with our plugins.lua table, we need to return lua tables in each file. So we need to combine the plugin and the config into a single lua table.
So one by one I moved each file from the after/plugins/
to the lua/plugins/
directory. Then I moved the plugin installation code from the plugins.lua
table and added a config
function to place the relocated config to.
Here’s an example:
return {
"ThePrimeagen/harpoon",
config = function()
local mark = require("harpoon.mark")
local ui = require("harpoon.ui")
vim.keymap.set("n", "<leader>a", mark.add_file, { desc = "Harpoon: Mark File" })
vim.keymap.set("n", "<C-e>", ui.toggle_quick_menu, { desc = "Toggle Harpoon Menu" })
vim.keymap.set("n", "<C-t>", function()
ui.nav_file(1)
end, { desc = "Harpoon File 1" })
vim.keymap.set("n", "<C-s>", function()
ui.nav_file(2)
end, { desc = "Harpoon File 2" })
vim.keymap.set("n", "<C-b>", function()
ui.nav_file(3)
end, { desc = "Harpoon File 3" })
vim.keymap.set("n", "<C-g>", function()
ui.nav_file(4)
end, { desc = "Harpoon File 4" })
end,
}
Before I only had “ThePrimeagen/harpoon”
in my plugins.lua
table and a separate file for the keymaps in after/plugin/
. Now both are combined in the harpoon.lua
file under lua/plugins/
.
After migrating all the files and removing the after/plugin/
directory I restarted Neovim and we were good!
The final step I took was to get rid of the lazy.lua
file I had and move it into the init.lua
file at the root of my configuration.
Here’s what it looks like now:
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
" - filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
" - branch=stable", - latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
vim.g.mapleader = " "
vim.g.maplocalleader = " "
require("lazy").setup("plugins", {
change_detection = {
notify = false,
},
})
require('exosyphon.globals')
require('exosyphon.remaps')
require('exosyphon.options')
vim.cmd("colorscheme tokyonight")
vim.cmd('hi IlluminatedWordText guibg=none gui=underline')
vim.cmd('hi IlluminatedWordRead guibg=none gui=underline')
vim.cmd('hi IlluminatedWordWrite guibg=none gui=underline')
and that was it! I now have lazy loading working across all my plugins and have a very extensible configuration that I can add more plugins to.
Conclusion
The migration took me about an hour or so because I started with an incomplete understanding of the lazy.nvim structure but after getting a better grasp, I was able to get everything migrated successfully and am really happy with how the new structure works. Have you migrated from Packer to lazy.nvim? Check out my original video on the topic. Here’s a link to my config.