Migrating from lazy.nvim to vim.pack

Steve Simkins March 31, 2026
Source

Like many others who are upgrading to Neovim 0.12.0, I decided to give vim.pack a try by following the excellent guide by Evgeni Chasnovski. I did encounter a few bumps that I figured I would document here just in case others find themselves stuck.

  • Symlinks - Bit more of a dummy move on my part, but I wasn't paying attention to my symlink setup that maps my git controlled repo ~/dotfiles/nvim to ~/.config/nvim and ended up missing some new folders I created. Re-linking helped fixed this, so if you have this kind of setup keep in mind to do this!

  • Multiple Folder Organization - Something I wanted to do originally is replicate the setup I had with lazy where each plugin was in it's own file. This is possible vim.pack, but it requires using a plugin directory that is adjacent to your init.lua file. I have a slightly different structure where this style didn't quite fit in, so I stuck with a single file setup instead.

  • Lazy Loading - The guide linked at the beginning has some great tips for how you can lazy load plugins based on different events, so I would highly recommend looking at which plugins don't need to be loaded immediately or only need to be loaded while in insert mode. I was able to shave an extra 10ms off my startup time!

Overall this resulted in a lean one file config for plugins that is only 117 lines long and has an average startup time of 35ms.

``lua -- ============================================================================ -- Colorscheme (must load at startup) -- ============================================================================ vim.pack.add({ "https://github.com/stevedylandev/compline-nvim", 'https://github.com/echasnovski/mini.nvim', }) vim.cmd.colorscheme('compline')

-- ============================================================================ -- Mini.nvim — startup modules -- ============================================================================

local win_config = function() local height = math.floor(0.618 vim.o.lines) local width = math.floor(0.618 vim.o.columns) return { anchor = 'NW', height = height, width = width, row = math.floor(0.5 (vim.o.lines - height)), col = math.floor(0.5 (vim.o.columns - width)), } end

require("mini.pick").setup({ mappings = { choose_marked = '', move_down = '', move_up = '', }, window = { config = win_config } })

vim.api.nvim_set_hl(0, "MiniPickMatchCurrent", { bg = vim.g.terminal_color_8 })

require('mini.icons').setup() vim.api.nvim_set_hl(0, 'MiniIconsAzure', { fg = vim.g.terminal_color_12 }) vim.api.nvim_set_hl(0, 'MiniIconsBlue', { fg = vim.g.terminal_color_4 }) vim.api.nvim_set_hl(0, 'MiniIconsCyan', { fg = vim.g.terminal_color_6 }) vim.api.nvim_set_hl(0, 'MiniIconsGreen', { fg = vim.g.terminal_color_2 }) vim.api.nvim_set_hl(0, 'MiniIconsGrey', { fg = vim.g.terminal_color_8 }) vim.api.nvim_set_hl(0, 'MiniIconsOrange', { fg = vim.g.terminal_color_3 }) vim.api.nvim_set_hl(0, 'MiniIconsPurple', { fg = vim.g.terminal_color_5 }) vim.api.nvim_set_hl(0, 'MiniIconsRed', { fg = vim.g.terminal_color_1 }) vim.api.nvim_set_hl(0, 'MiniIconsYellow', { fg = vim.g.terminal_color_11 })

require('mini.diff').setup({ view = { style = vim.go.number and 'sign' or 'number',

signs = {
  add = "+",
  change = "~",
  delete = "-",
  topdelete = "",
  changedelete = "▎",
  untracked = "+"
},

priority = 199,

}, }) require('mini.statusline').setup() require('mini.extra').setup()

-- ============================================================================ -- Deferred — loads right after startup via vim.schedule() -- ============================================================================ vim.schedule(function() vim.pack.add({ "https://github.com/christoomey/vim-tmux-navigator", })

require("mini.comment").setup({ mappings = { comment = 'gb', comment_visual = 'gb', textobject = 'gb' } })

require('mini.surround').setup({ mappings = { replace = 'cs', -- Replace surrounding }, })

require('mini.files').setup({ mappings = { close = '', go_in_plus = '' } }) end)

-- ============================================================================ -- Lazy — loads on InsertEnter -- ============================================================================ vim.api.nvim_create_autocmd('InsertEnter', { once = true, callback = function() require("mini.completion").setup({ mappings = { scroll_down = '', scroll_up = '', }, })

local gen_loader = require('mini.snippets').gen_loader require('mini.snippets').setup({ snippets = { gen_loader.from_lang(), }, }) MiniSnippets.start_lsp_server() end }) ``

All of my dotfiles can be found at github.com/stevedylandev/dotfiles!

Discussion in the ATmosphere

Loading comments...