Autocommands
Autocommands run Lua functions (or Vimscript) in response to Neovim events. They automate behaviors like formatting on save, highlighting on yank, and applying filetype-specific settings.
Core Idea
An autocmd says: "When event happens with pattern, run callback." Events include BufWritePre, BufEnter, FileType, InsertLeave, and dozens more.
The Lua API
vim.api.nvim_create_autocmd(event, {
group = augroup_id, -- optional: put in an augroup
pattern = "*.lua", -- file pattern or "*"
callback = function(args)
-- args.buf, args.file, args.match, etc.
end,
desc = "Description",
})
Augroups — Preventing Duplicate Autocmds
Always use augroup to group related autocmds. The { clear = true } option removes any existing autocmds in the group (prevents duplicates on config reload):
local augroup = vim.api.nvim_create_augroup
local autocmd = vim.api.nvim_create_autocmd
local my_group = augroup("MyGroup", { clear = true })
autocmd("BufWritePre", {
group = my_group,
pattern = "*",
callback = function()
-- runs before every save
end,
})
Essential Autocommands
1. Highlight on Yank
autocmd("TextYankPost", {
group = augroup("highlight_yank", { clear = true }),
callback = function()
vim.highlight.on_yank({
higroup = "IncSearch",
timeout = 150,
})
end,
desc = "Highlight yanked text",
})
2. Return to Last Cursor Position
autocmd("BufReadPost", {
group = augroup("last_cursor", { clear = true }),
callback = function()
local mark = vim.api.nvim_buf_get_mark(0, '"')
local lcount = vim.api.nvim_buf_line_count(0)
if mark[1] > 0 and mark[1] <= lcount then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
desc = "Return to last cursor on open",
})
3. Remove Trailing Whitespace on Save
autocmd("BufWritePre", {
group = augroup("trim_whitespace", { clear = true }),
pattern = "*",
callback = function()
local pos = vim.api.nvim_win_get_cursor(0)
vim.cmd([[%s/\s\+$//e]])
vim.api.nvim_win_set_cursor(0, pos)
end,
desc = "Remove trailing whitespace on save",
})
4. Auto-format on Save
autocmd("BufWritePre", {
group = augroup("auto_format", { clear = true }),
pattern = { "*.lua", "*.js", "*.ts", "*.py", "*.go" },
callback = function()
vim.lsp.buf.format({ async = false, timeout_ms = 3000 })
end,
desc = "Format on save",
})
5. Filetype-Specific Settings
autocmd("FileType", {
group = augroup("filetype_settings", { clear = true }),
pattern = { "python" },
callback = function()
vim.bo.tabstop = 4
vim.bo.shiftwidth = 4
vim.bo.expandtab = true
end,
})
autocmd("FileType", {
group = augroup("markdown_settings", { clear = true }),
pattern = { "markdown", "text" },
callback = function()
vim.wo.wrap = true
vim.wo.linebreak = true
vim.wo.spell = true
vim.opt_local.spelllang = "en_us"
end,
})
6. Close Certain Filetypes with q
autocmd("FileType", {
group = augroup("close_with_q", { clear = true }),
pattern = {
"qf", "help", "man", "notify",
"lspinfo", "spectre_panel", "checkhealth",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "q", "<cmd>close<cr>", {
buffer = event.buf,
silent = true,
})
end,
})
7. Auto-reload Files Changed Externally
autocmd({ "FocusGained", "BufEnter", "CursorHold", "CursorHoldI" }, {
group = augroup("auto_reload", { clear = true }),
callback = function()
if vim.fn.mode() ~= "c" and
vim.fn.getcmdwintype() == "" and
not vim.bo.modified then
vim.cmd("checktime")
end
end,
desc = "Reload file when changed externally",
})
8. Equalize Splits on Window Resize
autocmd("VimResized", {
group = augroup("equalize_splits", { clear = true }),
callback = function()
vim.cmd("tabdo wincmd =")
end,
})
Listing and Deleting Autocmds
-- List all autocmds
:autocmd
-- List autocmds in a group
:autocmd MyGroup
-- Delete an autocmd (Lua)
vim.api.nvim_del_autocmd(autocmd_id)
-- Clear a group
vim.api.nvim_clear_autocmds({ group = "MyGroup" })
Common Events Reference
| Event | When it fires |
|---|---|
| BufWritePre | Before writing a buffer |
| BufWritePost | After writing a buffer |
| BufEnter | When entering a buffer |
| BufLeave | When leaving a buffer |
| BufReadPost | After reading a buffer |
| FileType | After filetype is set |
| InsertEnter | Entering Insert mode |
| InsertLeave | Leaving Insert mode |
| TextYankPost | After yanking text |
| VimResized | Terminal window resized |
| FocusGained | Window gains focus |
| CursorHold | Cursor held still (updatetime) |
| LspAttach | After LSP attaches to buffer |
In LazyVim
LazyVim Context
LazyVim includes many of these essential autocommands by default (such as highlighting on yank, resizing splits, and closing certain windows with q). You can add your own custom autocommands in lua/config/autocmds.lua.
| Aspect | Vanilla Neovim | LazyVim |
|---|---|---|
| Autocmd Location | lua/config/autocmds.lua | lua/config/autocmds.lua (loaded automatically) |
| Highlight on Yank | Requires manual setup | Pre-configured |
| Equalize Splits | Requires manual setup | Pre-configured |
| Auto-format on save | Requires manual setup | Handled by conform.nvim (bundled) |