vimtricks.wiki Concise Vim tricks, one at a time.

How do I define a custom user command in Neovim Lua config that accepts arguments and has a description?

Answer

vim.api.nvim_create_user_command()

Explanation

Neovim's Lua API provides vim.api.nvim_create_user_command() for defining custom Ex commands that call Lua functions. Unlike the Vimscript :command approach, the Lua API lets you pass a table of options including a desc field (shown by which-key and :help) and define argument completion natively. This is the modern way to register project-specific or plugin commands in an init.lua config.

How it works

vim.api.nvim_create_user_command(
  'OpenInSplit',             -- command name (must start with uppercase)
  function(opts)             -- callback receives opts table
    vim.cmd('vsplit ' .. opts.args)
  end,
  {
    nargs = '?',             -- 0 or 1 argument
    complete = 'file',       -- tab-complete as filenames
    desc = 'Open a file in a vertical split',
  }
)

Key fields in the options table:

  • nargs — number of arguments: '0', '1', '*' (any), '?' (0 or 1), '+' (1 or more)
  • complete — completion type: 'file', 'buffer', 'command', or a custom Lua function
  • desc — human-readable description shown in which-key and :command MyCmd
  • bang — set to true to allow a ! suffix (opts.bang will be true if used)
  • range — set to true or '%' to accept a line range

Example

Create a command that toggles colorcolumn:

vim.api.nvim_create_user_command('ToggleColorColumn', function()
  if vim.o.colorcolumn == '' then
    vim.o.colorcolumn = '80'
  else
    vim.o.colorcolumn = ''
  end
end, { desc = 'Toggle 80-column guide' })

Then use :ToggleColorColumn in Neovim.

Tips

  • For buffer-local commands (e.g., in an ftplugin), use vim.api.nvim_buf_create_user_command(0, 'Name', fn, opts) — the 0 means current buffer
  • The opts.args field contains the argument string; use vim.split(opts.args, ' ') to get a list of words
  • Always add desc — it powers :Telescope commands, which-key popups, and :command output

Next

How do I use a count with text objects to operate on multiple text objects at once?