Skip to main content

Completion & Snippets

Completion Engine

LazyVim supports two completion engines. The variable vim.g.lazyvim_cmp controls which one to use:

ValueEngineDefault?
"auto"Auto-detect via :LazyExtrasDefault
"nvim-cmp"nvim-cmp (traditional)Installed by default
"blink.cmp"blink.cmp (faster, newer)Enable via coding.blink extra

Switch Between Engines

lua/config/options.lua
-- Force nvim-cmp
vim.g.lazyvim_cmp = "nvim-cmp"

-- Or force blink.cmp (after enabling the extra)
vim.g.lazyvim_cmp = "blink.cmp"

nvim-cmp (Default)

nvim-cmp is the traditional completion engine that ships with LazyVim by default.

Keymaps (Insert Mode)

KeyAction
<C-space>Manually trigger completion
<C-n> / <C-p>Next / previous item in menu
<C-y>Confirm selection
<C-e>Cancel / close menu
<C-d>Scroll documentation down
<C-f>Scroll documentation up
<CR>Confirm selected item
<Tab>Select next item (if configured via Supertab recipe)

Completion Sources

nvim-cmp fetches suggestions from these sources:

SourceProvides
LSPVariables, functions, types from language server
Snippets (LuaSnip)Code snippets
BufferWords already in current buffer
PathFile paths (./, ../)
TreesitterContext-aware tokens
LazyDevLua APIs for Neovim config files

Add a Custom Source

lua/plugins/cmp.lua
return {
"hrsh7th/nvim-cmp",
dependencies = { "hrsh7th/cmp-emoji" },
opts = function(_, opts)
table.insert(opts.sources, { name = "emoji" })
end,
}

Supertab (Tab for Completion)

Enable Tab to cycle completions and expand snippets:

lua/plugins/cmp.lua
return {
"hrsh7th/nvim-cmp",
opts = function(_, opts)
local has_words_before = function()
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
end
local cmp = require("cmp")
opts.mapping = vim.tbl_extend("force", opts.mapping, {
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif vim.snippet.active({ direction = 1 }) then
vim.schedule(function() vim.snippet.jump(1) end)
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif vim.snippet.active({ direction = -1 }) then
vim.schedule(function() vim.snippet.jump(-1) end)
else
fallback()
end
end, { "i", "s" }),
})
end,
}

blink.cmp (Alternative)

Faster, more modern completion engine. Enable it:

lua/plugins/extras.lua
return {
{ import = "lazyvim.plugins.extras.coding.blink" },
}

blink.cmp keymaps are similar — C-space triggers, C-n/C-p navigate, C-y/CR confirm.

Snippets (LuaSnip)

LazyVim uses LuaSnip for snippet expansion with nvim-cmp.

Default Snippet Keymaps

KeyModeAction
<C-k>InsertJump forward through snippet placeholders
<C-j>InsertJump backward through snippet placeholders

Built-in Snippets

LazyVim includes snippets for common languages via friendly-snippets:

  • Lua: fun, if, for, while, req (require)
  • JavaScript/TypeScript: fun, arrow, class, import, export
  • Python: def, class, if, for, print
  • HTML: div, a, img, link, script
  • Markdown: code, link, img, table

Trigger a Snippet

Type a snippet trigger word and press <C-space> to trigger completion, then select the snippet from the menu.

Example in a Python file:

  1. Type def
  2. Press <C-space>
  3. Select def snippet from menu
  4. Fill in function name, parameters, body — press <C-k> to jump between placeholders

Create Custom Snippets

Create ~/.config/nvim/snippets/ directory:

lua/plugins/snippets.lua
return {
"L3MON4D3/LuaSnip",
opts = function(_, opts)
local ls = require("luasnip")
-- Add a simple snippet
ls.add_snippets("lua", {
ls.snippet("log", {
ls.text_node('print("DEBUG: " .. '),
ls.insert_node(1),
ls.text_node(")"),
}),
})
-- Or load from snipmate format
-- require("luasnip.loaders.from_snipmate").load({ paths = "~/.config/nvim/snippets" })
end,
}

Snippet File Format (SnipMate)

~/.config/nvim/snippets/lua.json:

{
"log": {
"prefix": "log",
"body": "print(\"DEBUG: \" .. ${1:text})",
"description": "Print debug log"
}
}

Or ~/.config/nvim/snippets/lua.snippets:

snippet log "Print debug log"
print("DEBUG: " .. $1)
endsnippet

Completion Flow (Keyboard-Only)

1. Type code normally ← LSP sources show suggestions automatically
2. Press <C-space> to trigger ← Forces completion menu to appear
3. <C-n> / <C-p> to navigate ← Up/down through suggestions
4. <C-y> to accept ← Completes the word
5. If snippet: press <C-k> ← Jump to next placeholder
6. Type the placeholder value
7. <C-k> again when done ← Moves to next field or finishes
8. <C-e> to close menu ← Cancel if you changed your mind