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/keeprule
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)