Skip to main content

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 triggerWhen it loads
lazy = falseImmediately (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, or keys for lazy loading
  • Built-in unused plugins disabled in lazy.setup()
  • LSP updatetime set 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

What's Next