What is Find and Replace in Neovim?
Neovim's find-and-replace functionality goes far beyond simple text substitution. At its core lies the powerful :substitute command (abbreviated :s), combined with an expressive range system, regular expressions, and a suite of flags that give you surgical control over every change. Whether you're fixing a typo across a dozen files, refactoring variable names, or restructuring data with capture groups, Neovim provides everything you need without ever leaving your keyboard.
Why It Matters
Efficient find-and-replace is a fundamental skill for developers working with code, configuration files, documentation, or logs. A naive manual edit wastes time and introduces inconsistencies. Mastering Neovim's substitution mechanics allows you to:
- Perform project-wide refactors in seconds
- Apply conditional changes only where a pattern matches
- Review and confirm each replacement interactively to avoid mistakes
- Transform text layout using capture groups and backreferences
- Integrate search-and-replace into your editing muscle memory
Basic Search and Replace with :substitute
The fundamental syntax is:
:[range]s/pattern/replacement/[flags]
When no range is given, the substitution affects the current line. The simplest example replaces the first occurrence of "foo" with "bar" on the current line:
:s/foo/bar/
To replace all occurrences on the current line, append the g flag:
:s/foo/bar/g
To replace across the entire file, use the % range (which represents all lines):
:%s/foo/bar/g
Understanding Ranges
Ranges allow you to specify exactly which lines should be affected. They appear before the command and can be constructed from line numbers, marks, visual selections, or special symbols.
Common Range Specifiers
%— the entire buffer (all lines)1,5— lines 1 through 5 inclusive.,$— from the current line to the end of the file'<,'>— the last visual selection (automatically applied when you press:in visual mode)'a,'b— from mark a to mark b
Example: replace "old" with "new" only between lines 10 and 20, globally on each line:
:10,20s/old/new/g
Substitution Flags
Flags modify the behavior of the substitution. They are appended directly after the final delimiter.
g— replace all occurrences on each line, not just the firstc— confirm each substitution interactively (Neovim asksy/n/a/q/l/^E/^Y)i— case-insensitive matching for the patternI— case-sensitive matching (overrides any global settings)&— reuse the flags from the previous:sor:&commandp— print the affected line after the substitution
Example: interactive, case‑insensitive replacement across the whole buffer:
:%s/foo/bar/gic
Using Regular Expressions
Neovim's regex engine supports a wide range of patterns, but escaping rules can feel cumbersome. To reduce the need for backslashes, use the very magic modifier \v. With \v, most special characters ((){}[]+*?) lose their literal meaning and become regex operators without extra escaping.
Capture Groups and Backreferences
Capture groups allow you to extract parts of the match and reuse them in the replacement. Without \v, you must escape parentheses:
:%s/\(\w\+\) \(\w\+\)/\2, \1/g
With very magic, the syntax becomes much cleaner:
:%s/\v(\w+) (\w+)/\2, \1/g
In the replacement, \1, \2, etc. refer to the captured groups. You can also use \0 to insert the entire matched string.
Word Boundaries and Anchors
To restrict a match to whole words, use \< for start‑of‑word and \> for end‑of‑word boundaries. In very magic mode, you still need the backslashes for these:
:%s/\v<foo>/bar/g
Anchors ^ (beginning of line) and $ (end of line) are also frequently used:
:%s/\v^#\s*\zs.*/new comment text
The special atom \zs and \ze define the start and end of the actual replacement, letting you keep surrounding context intact.
Interactive Find and Replace
The c flag turns substitution into a dialogue. For each match, Neovim pauses and shows a prompt. You then choose:
y— substitute this matchn— skip this matcha— substitute this and all remaining matches (no more questions)q— quit (stop asking and don't substitute the current one)l— substitute this match and then quit (last one)^E(Ctrl+E) — scroll down^Y(Ctrl+Y) — scroll up
This is invaluable when you want to review each change in context. Example:
:%s/old_function/new_function/gc
Find and Replace in Visual Selection
To restrict replacements to a visually selected block, first enter visual mode (v, V, or Ctrl+v), select the desired text, then press :. Neovim automatically inserts the range '<,'>. Type your substitution command after it:
:'<,'>s/pattern/replacement/g
Only the selected lines (or block boundaries) will be affected. For block selections, note that the substitution still operates on whole lines; for character‑wise changes within a block, consider using a plugin or the :s with a narrower range.
Using the Global Command for Conditional Replacement
The :global command (:g) lets you run an Ex command on every line that matches a given pattern. The inverse is :v (or :vglobal), which runs the command on lines that do not match.
To replace "foo" with "bar" only on lines that contain "baz":
:g/baz/s/foo/bar/g
To delete all lines that do NOT contain "TODO":
:v/TODO/d
You can chain multiple commands by separating them with |:
:g/DEBUG/s/^/# / | s/\v\s+$//
This adds a comment prefix and removes trailing whitespace on every line containing "DEBUG".
Replacing Across Multiple Files
Neovim provides several commands for batch operations across buffers, arguments, or the quickfix list.
Using :argdo
The argument list (:args) contains files. You can populate it with :args *.lua or by opening files. Then apply a substitution to all of them:
:argdo %s/foo/bar/ge | update
The e flag suppresses errors when no match is found, and update writes each file only if it changed.
Using :bufdo
Similar to :argdo, but operates on all open buffers:
:bufdo %s/foo/bar/ge | update
Using the Quickfix List
After a search with :vimgrep or :grep, you can use :cdo to run a command on every quickfix entry:
:vimgrep /pattern/ *.lua
:cdo s/old/new/g | update
The related :cfdo works on files (not individual entries) in the quickfix list, avoiding duplicate edits per file.
Best Practices
- Test with a plain search first. Use
/patternto highlight matches before committing to a replacement. - Adopt
\vas your default. Very magic mode makes regex readable and reduces escaping mistakes. - Use the
cflag liberally. Interactive confirmation prevents catastrophic errors, especially on large files or unfamiliar patterns. - Leverage capture groups. Rearranging text with
\1,\2is far safer than rewriting by hand. - Combine
:gand:sfor precision. Target only lines that meet a condition, avoiding side‑effects. - Save before large replacements. A quick
:wand undo checkpoint give you a safety net. - Use the
eflag in batch commands. It prevents the command from aborting when a pattern is not found in some files. - Consider recording a macro for complex, multi‑step transformations. The substitution command is excellent, but macros can combine it with other motions.
Conclusion
Find and replace in Neovim is a deep, integrated system that rewards practice. Starting from the simple :s/old/new and gradually adopting ranges, flags, regex, and multi‑file operations, you can handle virtually any text manipulation task with speed and confidence. By internalizing these commands and best practices, you turn Neovim into a precision editing instrument that keeps your codebase clean and consistent without ever leaving the terminal.