Search and Replace
Neovim's search-and-replace system is one of the most powerful in any text editor. It uses regular expressions, supports range-limited substitution, can operate across multiple files, and provides real-time preview with inccommand.
The substitute command syntax is: :[range]s/pattern/replacement/[flags]
Once you know the parts, you can build any substitution precisely.
Basic Searching
/pattern → Search forward
?pattern → Search backward
n → Next match
N → Previous match
* → Search word under cursor (forward)
# → Search word under cursor (backward)
:noh → Clear search highlight
Enable Live Search Highlight
vim.opt.incsearch = true -- show matches as you type
vim.opt.hlsearch = true -- highlight all matches
vim.opt.ignorecase = true -- case insensitive by default
vim.opt.smartcase = true -- case sensitive if uppercase in pattern
The Substitute Command
:[range]s/{pattern}/{replacement}/[flags]
Ranges
| Range | Meaning |
|---|---|
| (none) | Current line only |
% | Entire file |
1,10 | Lines 1 to 10 |
'<,'> | Visual selection (auto-inserted) |
.,+5 | Current line + 5 lines |
.,/end/ | Current line to line containing "end" |
Flags
| Flag | Meaning |
|---|---|
g | Global — replace all on each line |
i | Case insensitive |
I | Case sensitive (override smartcase) |
c | Confirm each replacement |
e | Suppress "no match" errors |
n | Count matches (no replacement) |
Common Examples
" Replace first occurrence on current line
:s/old/new/
" Replace all on current line
:s/old/new/g
" Replace all in entire file
:%s/old/new/g
" Replace all, case insensitive
:%s/old/new/gi
" Replace all, ask for confirmation on each
:%s/old/new/gc (y/n/q/a/l at each prompt)
" Replace only in lines 10-20
:10,20s/old/new/g
" Replace in visual selection
:'<,'>s/old/new/g
" Count how many matches (no change)
:%s/pattern//gn
Live Substitution Preview
Enable real-time preview of replacements:
vim.opt.inccommand = "split" -- preview in split window
-- or
vim.opt.inccommand = "nosplit" -- preview inline only
Now as you type :%s/old/new, you see the changes highlighted in the buffer before pressing Enter.
Regex Patterns in Search
Neovim uses a variant of regex called "very magic mode":
" Standard (limited special chars)
/word
" Very magic: \v enables most regex chars without escaping
/\vword|other
" Examples with \v (very magic):
/\v\d{3}-\d{4} → phone number pattern
/\vfunction\s+\w+\( → function declaration
/\v(foo|bar)baz → foo or bar followed by baz
" Capture groups in substitute:
:%s/\v(\w+), (\w+)/\2 \1/g → swap "Last, First" to "First Last"
Substitute with Capture Groups
" Swap order: "LastName, FirstName" → "FirstName LastName"
:%s/\(\w\+\), \(\w\+\)/\2 \1/g
" In very magic mode (\v):
:%s/\v(\w+), (\w+)/\2 \1/g (cleaner)
" Add quotes around a value:
:%s/\vkey: (\w+)/key: "\1"/g
" Replace function calls:
:%s/\vlog\((.{-})\)/console.log(\1)/g
Global Command (:g)
:g runs a command on every line matching a pattern:
" Delete all blank lines
:g/^$/d
" Delete all lines containing "TODO"
:g/TODO/d
" Copy all lines matching pattern to end of file
:g/pattern/t$
" Run a substitute on all lines containing "import"
:g/import/s/from '/from "
" Print all matching lines (like grep)
:g/error/p
" Reverse: run command on non-matching lines
:v/pattern/command (or :g!/pattern/command)
Multi-File Search and Replace
Built-in Approach
" Open all JS files
:args **/*.js
" Do the replacement across all open args
:argdo %s/oldFunc/newFunc/ge | update
" Or for quickfix results from :vimgrep:
:vimgrep /pattern/ **/*.js
:cfdo %s/pattern/replacement/g | update
With Telescope (recommended — see Module 10)
<leader>sr → Telescope live grep + replace (with plugin)
Search and Replace with Confirmation
:%s/old/new/gc
At each match, you see:
replace with new (y/n/q/a/l/?)?
y - yes for this one
n - skip this one
q - quit
a - all remaining (no more asking)
l - yes for this one then quit (last)
The cgn Pattern (Modern Replace Workflow)
A modern alternative to global substitute using gn and the dot command:
/target → search for the target word
cgn → change the next match (enters insert)
replacement → type the replacement
Esc → back to Normal
n. → find next match, apply same change
n.n.n. → repeat as needed
This is the "find, change, repeat" workflow. It's better than %s when you want to selectively replace some (not all) occurrences.