← Back to DevBytes

Neovim Find and Replace: Complete Guide

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:

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

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.

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:

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

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.

— Ad —

Google AdSense will appear here after approval

← Back to all articles