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. As of Neovim 0.11 (released March 2025), the LSP client, autocompletion, and default IDE-style keymaps are built in — a modern config no longer needs the plugins that were mandatory a few years ago.
TL;DR
- Neovim is a modal editor: keys do different things in Normal, Insert, Visual, Command-line, and Terminal mode. Master the
operator + motiongrammar first. - Neovim 0.11 (March 2025) ships a built-in LSP client with default keymaps (
grnrename,gracode action,grrreferences) — nonvim-lspconfigrequired to get started. - Configure in Lua via
~/.config/nvim/init.lua;lazy.nvimis the de facto plugin manager. - Run
:checkhealthafter every config change — it catches the clipboard, parser, and provider failures that silently break a setup.
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. Many developers leave window management to tmux and use Neovim splits sparingly — tmux panes survive an editor crash, Neovim windows do not.
# 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
-- Override or extend a config with vim.lsp.config (replaces the old setup{})
vim.lsp.config('lua_ls', {
settings = { Lua = { diagnostics = { globals = { 'vim' } } } },
})Neovim 0.11 (March 2025) split server configuration (vim.lsp.config) from activation (vim.lsp.enable), replacing the old require('lspconfig').server.setup{} pattern. The same release added default keymaps the moment a server attaches, so you no longer have to wire them yourself:
| Default keymap (0.11+) | Action |
|---|---|
| grn | Rename symbol (vim.lsp.buf.rename) |
| gra | Code action (vim.lsp.buf.code_action) |
| grr | List references (vim.lsp.buf.references) |
| gri | Go to implementation (vim.lsp.buf.implementation) |
| gO | Document symbols (vim.lsp.buf.document_symbol) |
| Ctrl-S (insert) | Signature help (vim.lsp.buf.signature_help) |
| [d / ]d | Previous / next diagnostic |
Note the deliberate break from older tutorials: the defaults use gr prefixes (grn, gra), not the <leader> mappings most pre-0.11 guides teach. Enable inline completion with vim.lsp.completion.enable(). For deeper scripting of the LSP client and the vim.* namespace, see the Neovim Lua guide. For automatic server installation, the popular mason.nvim and mason-lspconfig.nvim plugins 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 linesWhen should you not use Neovim?
- You need a zero-config IDE today. A from-scratch Neovim setup is hours of Lua before it matches VS Code out of the box. Start from a distribution like kickstart.nvim or LazyVim if you want batteries included.
- Heavy GUI debugging or visual tooling. nvim-dap exists, but for step-through debugging of complex runtimes a full IDE (JetBrains, VS Code) is still less friction.
- Pair programming with non-Vim users. Modal editing has a real learning curve; on a shared screen it can slow a team down rather than speed it up.
References
- Neovim documentation — official user manual and API reference.
- Neovim 0.11 release notes — the native LSP changes, default keymaps, and built-in completion covered above.
- 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.