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

How do I deeply merge two Lua tables in Neovim config using vim.tbl_deep_extend?

Answer

vim.tbl_deep_extend('force', defaults, overrides)

Explanation

vim.tbl_deep_extend() recursively merges Lua tables, making it the standard pattern for merging default options with user overrides in Neovim configs and plugins. Unlike vim.tbl_extend(), it merges nested tables instead of overwriting them entirely.

How it works

  • First argument is the behavior: 'force' (second table wins) or 'keep' (first table wins)
  • Additional arguments are tables to merge, processed left to right
  • Nested tables are merged recursively
  • Non-table values at the same key follow the force/keep rule

Example

local defaults = {
  border = 'rounded',
  width = 80,
  lsp = { timeout = 1000, retries = 3 },
}

local user_opts = {
  border = 'single',           -- overrides default
  lsp = { retries = 5 },      -- merges into nested lsp table
}

local result = vim.tbl_deep_extend('force', defaults, user_opts)
-- {
--   border = 'single',
--   width = 80,
--   lsp = { timeout = 1000, retries = 5 },
-- }

Tips

  • With 'keep', the first table's values take priority — useful for applying fallbacks
  • Use vim.tbl_extend() (non-deep) when nested tables should be fully replaced
  • To handle user config with defaults: vim.tbl_deep_extend('force', defaults, user_config or {})
  • To clone a table: vim.tbl_deep_extend('force', {}, original_table)

Next

How do I enable matchit so % jumps between if/else/end style pairs?