Performance Tuning
Neovim with many plugins can become slow if not carefully managed. This lesson shows how to profile and optimize.
Measure Startup Time
# Measure startup time from the command line
nvim --startuptime /tmp/startup.log && nvim +quit
cat /tmp/startup.log | sort -k2 -rn | head -20
" Inside Neovim with lazy.nvim
:Lazy profile
Lazy Loading (The Most Impactful Fix)
Every plugin that doesn't lazy-load increases startup time:
-- Bad: loads immediately
{
"heavy/plugin",
}
-- Good: loads only when needed
{
"heavy/plugin",
event = { "BufReadPost", "BufNewFile" }, -- on file open
-- or:
cmd = "HeavyCommand", -- on command
-- or:
ft = { "python" }, -- on filetype
-- or:
keys = { "<leader>xx" }, -- on keypress
}
Lazy Loading Priority
| Load trigger | When it loads |
|---|---|
lazy = false | Immediately (only for critical plugins) |
event = "VimEnter" | Right after Vim starts |
event = "VeryLazy" | After everything else |
event = "BufReadPost" | When opening a file |
ft = "python" | Only for Python files |
cmd = "Cmd" | Only when command is used |
keys = { "..." } | Only when key is pressed |
Disable Unused Built-ins
in lazy.setup() options
performance = {
rtp = {
disabled_plugins = {
"gzip",
"matchit",
"matchparen",
"netrwPlugin", -- if using neo-tree
"tarPlugin",
"tohtml",
"tutor",
"zipPlugin",
},
},
},
Large File Optimizations
lua/config/autocmds.lua
vim.api.nvim_create_autocmd("BufReadPre", {
callback = function(args)
local max_filesize = 500 * 1024 -- 500KB
local ok, stats = pcall(vim.loop.fs_stat, args.file)
if ok and stats and stats.size > max_filesize then
-- Disable heavy features for large files
vim.b.large_file = true
vim.opt_local.syntax = "off"
vim.opt_local.swapfile = false
vim.opt_local.foldmethod = "manual"
vim.opt_local.undolevels = -1
vim.cmd("LspStop")
vim.notify("Large file: disabling LSP, syntax, undo", vim.log.levels.WARN)
end
end,
})
Treesitter Performance
-- Disable for large files
highlight = {
enable = true,
disable = function(lang, buf)
local max_filesize = 100 * 1024 -- 100KB
local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
if ok and stats and stats.size > max_filesize then
return true
end
end,
},
Check Memory Usage
# Memory used by Neovim process
ps -o pid,rss,comm -p $(pgrep nvim)
# Inside Neovim
:lua print(collectgarbage("count") .. " KB Lua memory")
Profiling Lua Code
-- Profile a specific plugin config
local start = vim.loop.hrtime()
require("heavy.plugin").setup({})
local end_ = vim.loop.hrtime()
print(("Setup took %.2f ms"):format((end_ - start) / 1e6))
Quick Performance Checklist
- All plugins use
event,cmd,ft, orkeysfor lazy loading - Built-in unused plugins disabled in
lazy.setup() - LSP
updatetimeset to 300 - Large file autocmd disables heavy features
- Treesitter highlight disabled for large files
-
swapfile = false(avoids disk I/O) - Startup time measured with
:Lazy profile