Skip to main content

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", "&lt;cmd&gt;close&lt;cr&gt;", {
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​

EventWhen it fires
BufWritePreBefore writing a buffer
BufWritePostAfter writing a buffer
BufEnterWhen entering a buffer
BufLeaveWhen leaving a buffer
BufReadPostAfter reading a buffer
FileTypeAfter filetype is set
InsertEnterEntering Insert mode
InsertLeaveLeaving Insert mode
TextYankPostAfter yanking text
VimResizedTerminal window resized
FocusGainedWindow gains focus
CursorHoldCursor held still (updatetime)
LspAttachAfter 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.

AspectVanilla NeovimLazyVim
Autocmd Locationlua/config/autocmds.lualua/config/autocmds.lua (loaded automatically)
Highlight on YankRequires manual setupPre-configured
Equalize SplitsRequires manual setupPre-configured
Auto-format on saveRequires manual setupHandled by conform.nvim (bundled)

What's Next​