Lazy Loading
May 15, 2026 · View on GitHub
leanpack.nvim provides multiple lazy loading mechanisms to optimize Neovim startup time.
Overview
Lazy loading defers plugin activation until needed. This reduces startup time by only loading plugins when you use their features.
leanpack.nvim implements four lazy loading trigger types:
- Event - Load when a Neovim event fires
- Command - Load when a user command is called
- Keymap - Load when a key is pressed
- Filetype - Load when a file type is detected
Event Trigger
Load a plugin when a Neovim event occurs.
Syntax
return {
'plugin/name',
event = 'EventName',
}
Common Events
| Event | Description |
|---|---|
VeryLazy | After UIEnter (default for lazy plugins) |
BufReadPre | Before reading a buffer |
BufReadPost | After reading a buffer |
BufNew | For new buffers |
TabEnter | When switching tabs |
InsertEnter | When entering insert mode |
CmdlineEnter | When entering command line |
Examples
-- Load on InsertEnter event
return {
'windwp/nvim-autopairs',
event = 'InsertEnter',
opts = {},
}
-- Load on multiple events
return {
'user/plugin',
event = { 'InsertEnter', 'CmdlineEnter' },
}
-- Load with file pattern
return {
'user/lua-syntax',
event = 'BufReadPre *.lua',
}
-- Load very lazily (after startup)
return {
'user/plugin',
event = 'VeryLazy',
}
Command Trigger
Load a plugin when a user command is invoked.
Syntax
return {
'plugin/name',
cmd = 'CommandName',
}
Examples
-- Single command
return {
'nvim-tree/nvim-tree.lua',
cmd = { 'NvimTreeToggle', 'NvimTreeFocus' },
opts = {},
}
-- Multiple commands
return {
'user/plugin',
cmd = { 'Cmd1', 'Cmd2', 'Cmd3' },
}
How It Works
- leanpack.nvim creates a temporary stub command
- When the user runs the command, the stub loads the plugin
- The stub deletes itself and runs the actual command
Keymap Trigger
Load a plugin when a key is pressed.
Syntax
return {
'plugin/name',
keys = 'keyseq',
}
Or with options:
return {
'plugin/name',
keys = {
{ 'keyseq', function() ... end, mode = 'n', desc = 'Description' },
},
}
Examples
-- Simple key sequence
return {
'folke/flash.nvim',
keys = 's',
}
-- With function
return {
'folke/flash.nvim',
keys = {
{ 's', function() require('flash').jump() end, mode = { 'n', 'x', 'o' }, desc = 'Flash' },
{ 'S', function() require('flash').treesitter() end, mode = { 'n', 'x', 'o' }, desc = 'Flash Treesitter' },
},
}
-- With command
return {
'user/plugin',
keys = { '<leader>p', '<cmd>PluginCmd<cr>', mode = 'n', desc = 'Run Plugin' },
}
How It Works
- leanpack.nvim creates a temporary keymap
- When the key is pressed, the plugin loads
- The keymap deletes itself and re-feeds the keystrokes
Filetype Trigger
Load a plugin when a file type is detected.
Syntax
return {
'plugin/name',
ft = 'filetype',
}
Examples
-- Single filetype
return {
'rust-lang/rust.vim',
ft = 'rust',
}
-- Multiple filetypes
return {
'user/plugin',
ft = { 'lua', 'vim', 'python' },
}
Critical: Event Re-triggering
When using filetype triggers, leanpack.nvim automatically re-triggers buffer events to ensure LSP/Treesitter attaches:
-- After loading, leanpack.nvim does:
vim.api.nvim_exec_autocmds("BufReadPre", { buffer = bufnr })
vim.api.nvim_exec_autocmds("BufReadPost", { buffer = bufnr })
vim.api.nvim_exec_autocmds("FileType", { buffer = bufnr })
This ensures that newly loaded plugins analyze the current buffer.
Require/Module Trigger
Load a plugin automatically when its main Lua module is required.
Syntax
Leanpack natively intercepts require calls matching either:
- The explicit
mainfield defined in the spec. - The implicitly auto-detected main module name.
return {
'nvimtools/none-ls.nvim',
-- Because `opts` is here, if no `main` is present leanpack deduces it as `null-ls`.
-- Thus, `require('null-ls')` automatically triggers loading.
opts = {},
}
-- Or with explicit main
return {
'user/repo',
main = 'custom_module', -- require('custom_module') will load this!
}
How It Works
- leanpack.nvim installs a non-intrusive lookup loader in
package.loadersat startup. - When code calls
require('module_name'), it resolves against the plugin'smainreference. - If it matches an unloaded plugin, it loads it immediately and caches the module.
Comparison
| Trigger | Best For | Overhead |
|---|---|---|
| Event | General features | Very low |
| Command | CLI tools | Very low |
| Keymap | User-facing features | Low |
| Filetype | Language tools | Low |
| Module | Autoload via require | Very low |
Best Practices
1. Choose the Right Trigger
- UI plugins → Command or keymap trigger
- Language servers → Filetype trigger
- General plugins → Event trigger
- Colorscheme → No trigger (load eagerly)
2. Use Priority for Ordering
-- Load colorschemes early
return {
'folke/tokyonight.nvim',
priority = 1000,
config = function()
vim.cmd('colorscheme tokyonight')
end,
}
3. Group Dependencies
Make sure dependencies are loaded before their parent:
return {
'nvim-telescope/telescope.nvim',
cmd = 'Telescope',
dependencies = {
'nvim-lua/plenary.nvim',
},
}
Performance
leanpack.nvim's lazy loading is optimized:
- Self-cleaning package.loaders - Installs a lightweight loader at position 2 for module-based lazy loading, then auto-removes it once all module-triggered plugins are loaded (unlike lazy.nvim's permanent interception)
- Self-destructing triggers - Autocmds, commands, and keymaps delete themselves after first trigger
- O(V + E) dependency resolution - Efficient topological sorting
Next Steps
- Commands - CLI reference
- Troubleshooting - Common issues