Neovim is a modern, extensible fork of Vim that keeps full backward compatibility while adding first-class Lua scripting, a built-in LSP client, Tree-sitter integration, and asynchronous job control. It is designed for developers who want a fast, keyboard-driven editor that can be shaped into a full IDE — see the Neovim cheat sheet for a quick reference.
What are Neovim's modes?
Neovim is a modal editor — the meaning of each key depends on which mode you are in. Understanding modes is the single most important concept for productive editing.
| Mode | Enter with | Purpose |
|---|---|---|
| Normal | Esc | Navigate, delete, copy, paste, run commands |
| Insert | i / a / o | Type text into the buffer |
| Visual | v / V / Ctrl-v | Select text (character, line, or block) |
| Command-line | : | Execute Ex commands, search & replace |
| Terminal | :terminal | Run a shell inside a Neovim buffer |
How do Neovim operators and motions combine?
Neovim commands follow the grammar operator + [count] + motion. Learning a handful of operators and motions gives you a combinatorial explosion of editing power.
Common Operators
| Operator | Action |
|---|---|
| d | Delete |
| c | Change (delete + enter Insert mode) |
| y | Yank (copy) |
| > | Indent right |
| < | Indent left |
| gq | Format / rewrap text |
| gu / gU | Lowercase / uppercase |
Common Motions
w / b → forward / backward by word
e → end of word
0 / $ → start / end of line
gg / G → top / bottom of file
f{char} → jump to next {char} on the line
t{char} → jump to just before {char}
/{pattern} → search forward
?{pattern} → search backward
% → matching bracketCombine them: d2w deletes two words, ci" changes the text inside quotes, yG yanks from the cursor to the end of the file.
What are Neovim text objects?
Text objects let you operate on structured chunks of text. Prefix with i for inner (contents only) or a for around (including delimiters).
iw / aw
Inner / around word
diwi" / a"
Inside / around double quotes
ci"i( / a(
Inside / around parentheses
da(i{ / a{
Inside / around curly braces
yi{it / at
Inside / around HTML/XML tag
citip / ap
Inner / around paragraph
dapHow do Neovim registers work?
Registers are named storage slots for yanked or deleted text. Prefix a command with "{reg} to target a specific register.
| Register | Description |
|---|---|
| " | Default (unnamed) register |
| 0 | Last yank |
| 1-9 | Last 9 deletes (stack) |
| a-z | Named registers (you choose) |
| + | System clipboard |
| _ | Black hole (discard) |
| . | Last inserted text |
| % | Current filename |
| : | Last command-line command |
Example: "ayy yanks the current line into register a, and "ap pastes it. Use "+y to copy to the system clipboard.
Buffers, Windows & Tabs
Neovim separates the concepts of files (buffers), viewports (windows), and layouts (tabs). A single file can be displayed in multiple windows across multiple tabs.
# Buffers
:e file.lua Open a file in a new buffer
:bnext / :bprev Navigate buffers
:ls List all buffers
:bd Close current buffer
# Windows (splits)
:split / :vsplit Horizontal / vertical split
Ctrl-w h/j/k/l Move between windows
Ctrl-w = Equalize window sizes
Ctrl-w o Close all other windows
# Tabs
:tabnew New tab
gt / gT Next / previous tabHow do I enable the built-in LSP in Neovim?
Neovim ships with a built-in Language Server Protocol client that provides IDE features like go-to-definition, autocomplete, hover docs, rename, and diagnostics — all without plugins.
-- init.lua: minimal LSP setup (Neovim 0.11+)
vim.lsp.enable('lua_ls') -- enable lua-language-server
vim.lsp.enable('ts_ls') -- enable typescript-language-server
-- Common keymaps (set in an LspAttach autocmd)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition)
vim.keymap.set('n', 'gr', vim.lsp.buf.references)
vim.keymap.set('n', 'K', vim.lsp.buf.hover)
vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename)
vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action)
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev)
vim.keymap.set('n', ']d', vim.diagnostic.goto_next)For automatic server installation, the popular mason.nvim and mason-lspconfig.nvim plugins can manage language server binaries for you.
What does Tree-sitter give Neovim?
Neovim integrates Tree-sitter for fast, accurate syntax highlighting and code-aware text objects. Instead of regex-based highlighting, Tree-sitter builds a real parse tree of your code.
-- Install parsers (via nvim-treesitter plugin)
:TSInstall lua typescript python rust
-- Tree-sitter powered text objects (with nvim-treesitter-textobjects)
-- vaf → select outer function
-- vic → select inner class
-- ]m → jump to next methodHow do I configure Neovim with Lua?
Neovim uses init.lua (or the legacy init.vim) located in ~/.config/nvim/. Lua is the recommended language for all new configuration.
-- ~/.config/nvim/init.lua
-- Options
vim.opt.number = true -- line numbers
vim.opt.relativenumber = true -- relative line numbers
vim.opt.tabstop = 2 -- tab width
vim.opt.shiftwidth = 2 -- indent width
vim.opt.expandtab = true -- spaces instead of tabs
vim.opt.signcolumn = 'yes' -- always show sign column
vim.opt.clipboard = 'unnamedplus' -- use system clipboard
vim.opt.ignorecase = true -- case-insensitive search
vim.opt.smartcase = true -- unless uppercase is used
-- Leader key
vim.g.mapleader = ' '
-- Keymaps
vim.keymap.set('n', '<leader>w', ':w<CR>')
vim.keymap.set('n', '<leader>q', ':q<CR>')
vim.keymap.set('n', '<Esc>', ':nohlsearch<CR>')How do I manage Neovim plugins?
lazy.nvim is the de facto standard plugin manager. It supports lazy loading, lockfiles, a UI dashboard, and automatic dependency resolution.
-- Bootstrap lazy.nvim (place at top of init.lua)
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not vim.uv.fs_stat(lazypath) then
vim.fn.system({
'git', 'clone', '--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require('lazy').setup({
{ 'nvim-telescope/telescope.nvim', -- fuzzy finder
dependencies = { 'nvim-lua/plenary.nvim' } },
{ 'nvim-treesitter/nvim-treesitter', build = ':TSUpdate' },
{ 'neovim/nvim-lspconfig' }, -- LSP configs
{ 'hrsh7th/nvim-cmp' }, -- autocompletion
})Essential Plugins
telescope.nvim
Fuzzy finder for files, grep, buffers, and more
:Telescope find_filesnvim-cmp
Autocompletion engine with LSP, snippet, and path sources
Ctrl-n / Ctrl-poil.nvim
File explorer as an editable buffer
:Oilgitsigns.nvim
Git signs in the gutter, inline blame, hunk actions
:Gitsigns preview_hunkconform.nvim
Formatter integration (prettier, stylua, etc.)
:ConformFormatnvim-lint
Async linter integration (eslint, ruff, etc.)
Runs on saveWhat are common Neovim pitfalls?
- Clipboard not working. Setting
vim.opt.clipboard = 'unnamedplus'requires a system provider: installxcliporxselon X11,wl-clipboardon Wayland, or usepbcopy/pbpasteon macOS. Run:checkhealth providerto confirm. - Skipping :checkhealth.
:checkhealthsurfaces missing providers, broken Tree-sitter parsers, LSP server issues, and clipboard problems. Run it after every major config change. - Leader-key conflicts. Set
vim.g.mapleaderbefore loading lazy.nvim and any plugin specs — otherwise plugin keymaps bind to the wrong leader and your custom mappings silently fail. - Lazy-loading order. Plugins lazy-loaded by event or filetype won't run their
configon startup. If a colorscheme or LSP plugin must load eagerly, setlazy = falseand usepriority = 1000for the colorscheme. - init.vim shadows init.lua. Neovim loads only one entry point. If both
~/.config/nvim/init.vimandinit.luaexist,init.vimwins and your Lua config is ignored. Delete the legacy file when migrating.
Macros
Record a sequence of keystrokes and replay them. This is one of Neovim's most powerful features for repetitive edits.
q{reg} Start recording into register {reg}
q Stop recording
@{reg} Play macro from register {reg}
@@ Repeat last played macro
5@a Play macro 'a' five times
# Example: wrap each line in quotes
qa Record into register a
0i"<Esc> Go to start, insert "
A"<Esc> Go to end, append "
j Move to next line
q Stop recording
99@a Apply to next 99 linesReferences
- Neovim documentation — official user manual and API reference.
- folke/lazy.nvim — modern plugin manager with lazy loading and lockfile.
- neovim/nvim-lspconfig — community-maintained configurations for the built-in LSP client.
- Tree-sitter docs — the parser generator powering Neovim's syntax highlighting.
- nvim-treesitter/nvim-treesitter — Tree-sitter integration plugin with parsers for 200+ languages.
- Learn Vim in Y Minutes — concise tour of the modal editing model Neovim inherits.
See the Neovim Cheat Sheet for a quick reference of common keybindings.