← Back to DevBytes

Helix Find and Replace: Complete Guide

What Is Find and Replace in Helix?

Helix is a modal text editor inspired by Kakoune and Neovim, built from the ground up with modern features like tree-sitter syntax highlighting, multiple cursors, and a powerful built-in find and replace system. Unlike many editors that rely on external plugins for advanced search operations, Helix ships with an integrated, keyboard-driven find and replace workflow that works seamlessly across single files, multiple selections, and entire projects.

The find and replace mechanism in Helix operates through a combination of buffer-specific search commands and a dedicated :replace command that respects selections. The core philosophy is select first, then act — you identify what you want to change, select it using Helix's powerful selection primitives, and then apply transformations only to those selections. This approach eliminates the need for complex regex lookaheads or lookbehinds in many cases, because you can visually or structurally narrow down targets before executing a replacement.

Why Find and Replace Matters in Helix

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Efficient text manipulation is the heart of any editor, and Helix's design choices make find and replace particularly important for several reasons:

Getting Started: Basic Search

Before you can replace text, you need to find it. Helix uses a Kakoune-inspired search model. From normal mode, press / to search forward or ? to search backward. The search is incremental — as you type, the cursor jumps to the first match.

# In normal mode, type:
/function

# This highlights all occurrences of "function" in the buffer
# Press Enter to commit the search, or Esc to cancel
# Use n / N to jump to next / previous match

The search pattern supports full regex syntax. For example, to find all words starting with "get" followed by a capital letter:

/\bget[A-Z]\w+

Once you have a match highlighted, you can extend your selection using Helix's selection manipulation commands.

Single-Selection Replace: The :replace Command

The primary replacement mechanism in Helix is the :replace command (aliased as :re). It operates on the current selection(s). The syntax is straightforward:

:replace <pattern> <replacement>

# Aliases:
:re <pattern> <replacement>

# Examples:
:re true false        # Replace "true" with "false" in current selection
:re \b\d+\b "NUMBER"  # Replace standalone numbers with "NUMBER"

By default, :replace replaces all occurrences of the pattern within each selection. If you want to replace only the first occurrence in each selection, add the /c flag (confirm). This flag also enables interactive confirmation for each match.

Replacement Flags

Helix provides several flags to control replacement behavior:

# Replace all "foo" with "bar", case-insensitive, with confirmation
:re /i /c foo bar

# Replace literal "a[0]" (not regex) with "array[0]"
:re /x a[0] array[0]

Working with Multiple Selections

Helix truly shines when you combine find and replace with multiple selections. Here's a common workflow:

  1. Search for a pattern using /
  2. Select all matches with % (select_all) or manually add selections with n
  3. Run :replace to transform all selections at once
# Step-by-step example:
# 1. Search for all "const" declarations
/const\s+\w+

# 2. Select all matches in the buffer
%

# 3. Replace "const" with "let" within those selections
:re const let

# Now all "const" declarations become "let" declarations

You can also narrow selections before replacing. For instance, after selecting all matches with %, use Alt-s to split selections by a delimiter, or use Alt-_ to remove selections that don't contain a pattern.

# Select all lines containing "TODO"
/TODO
%

# Now replace "TODO" with "FIXME" only on those lines
:re TODO FIXME

# Or split selections further:
# Use Alt-s to split by spaces, then replace specific words

Replacing Within Structural Boundaries (Tree-sitter)

One of Helix's most powerful features is its ability to select syntactic nodes using tree-sitter. This allows you to confine replacements to specific code structures without writing complex boundary regexes.

# Inside a function body:
# 1. Move cursor inside a function
# 2. Select the entire function body with Alt-f (select_function)
# 3. Replace all "var" with "let" ONLY within that function body
:re var let

# Replace within a class definition:
# 1. Move cursor to a class
# 2. Alt-c selects the class
# 3. Replace "self." with "this." only inside that class
:re self\. this.

Common tree-sitter selection keys:

These structural selections compound beautifully with replace operations. You can select multiple functions (using % after a search or by manually adding selections with Alt-n) and replace across all of them simultaneously.

Project-Wide Find and Replace

Helix supports workspace-wide search and replace through its picker and grep integration. The workflow differs slightly from buffer-local operations.

Using the Workspace Picker

Press Space / (or Space f for file picker) to open the workspace picker in fuzzy search mode. To perform a global search, use:

# In normal mode:
Space /          # Open workspace search picker
# Type your pattern and press Enter
# All matches across the workspace appear in the picker
# Use Ctrl-c to copy the results, or select files to open

To replace across all matching files, you can use the :rsearch command combined with :replace in a macro-like workflow, or pipe the results through Helix's command system.

Using :rsearch and Quickfix

# Search for a pattern across the workspace
:rsearch oldFunctionName

# This populates the quickfix list with all occurrences
# Navigate through matches with Space ] and Space [
# For each file, open it, select matches with %, and run:
:re oldFunctionName newFunctionName

# Then save and move to the next file

Using External Grep with Helix

For more complex project-wide replacements, you can use external tools and leverage Helix's ability to open files at specific locations:

# From your terminal (outside Helix):
grep -rn "oldImport" src/ | helix --line-number

# Or within Helix's integrated terminal:
# Use Ctrl-z to suspend, run sed replacements, then resume
# Or use :sh to run a shell command while Helix stays open
:sh sed -i 's/oldImport/newImport/g' src/**/*.rs

Regex Capture Groups in Replacements

Helix supports regex capture groups in the replacement string using $1, $2, etc., or named groups with ${name}. This is essential for rearranging text.

# Swap two words separated by a comma
:re (\w+),\s*(\w+) $2, $1

# Example: "apple, banana" becomes "banana, apple"

# Convert snake_case to camelCase within selections
:re _([a-z]) \U$1

# Example: "user_name" becomes "userName" (with uppercase N)

# Add quotes around numbers
:re \b(\d+)\b "$1"

# Rearrange function parameters
:re func\((\w+),\s*(\w+)\) func($2, $1)

Helix uses Rust's regex engine, which supports:

Case Transformation in Replacements

Helix supports case modifiers within replacement strings, prefixed with \:

# \u - uppercase next character
# \U - uppercase until \E or end
# \l - lowercase next character
# \L - lowercase until \E or end
# \E - end case transformation

# Capitalize first letter of each word
:re \b(\w)(\w*)\b \u$1\L$2

# Example: "hello world" becomes "Hello World"

# Force entire match to uppercase
:re \w+ \U$0

# Force entire match to lowercase
:re \w+ \L$0

Interactive Confirmation Mode

When you need fine-grained control over each replacement, use the /c flag. Helix enters a confirmation loop where you can inspect each match before deciding.

# Replace "old" with "new", confirming each
:re /c old new

# During confirmation:
# y - yes, replace this match and move to next
# n - no, skip this match and move to next
# a - yes to all remaining (stop confirming)
# q - quit, stop all remaining replacements
# Esc - same as quit

This mode is invaluable for refactoring where context matters — you might want to replace a variable name only in certain scopes but not others, and the structural selection approach isn't granular enough.

Replacing Across Multiple Files with Macros

Helix supports recorded macros (using Q to record and q to replay). You can combine this with find and replace for repetitive multi-file operations.

# Record a macro that:
# 1. Opens a file from the picker
# 2. Performs a search
# 3. Selects all matches
# 4. Runs a replace
# 5. Saves and closes

# In normal mode:
Q w                     # Start recording to register w
Space f                 # Open file picker
# (select file manually, press Enter)
/old_pattern            # Search
%                       # Select all matches
:re old_pattern new_val # Replace
:x                      # Save and close
q                       # Stop recording

# Now replay with:
Space f                 # Open picker
# (select next file)
q w                     # Replay macro on that file

Replacing with the Pipe Command

Helix can pipe selections through external commands and capture the output back into the buffer. This is effectively a "replace with shell command output" feature.

# Select a JSON blob, pipe through jq to format it
# 1. Select the text (e.g., with Alt-p for paragraph)
# 2. Press | (pipe)
# 3. Type: jq .
# The selection is replaced with the formatted output

# Sort lines within a selection
# 1. Select multiple lines
# 2. | sort -r
# Selection is replaced with reversed sorted lines

# Base64 encode a selection
# 1. Select text
# 2. | base64

This pipe-based replacement is distinct from :replace but serves a similar transformative purpose. It's especially useful for formatting, encoding, or processing text with external tools.

Common Workflows and Patterns

Renaming a Variable Across a File

# 1. Move cursor to the variable
# 2. Use * (or Alt-o) to select the word under cursor
# 3. % to select all occurrences in the buffer
# 4. :re old_name new_name
# Done — all occurrences are renamed

Adding a Prefix to Multiple Lines

# 1. Select multiple lines (use Shift-J to extend downward)
# 2. Run replace with ^ anchor
:re ^ "// "

# This adds "// " to the beginning of each selected line
# Equivalent to commenting out those lines

Removing Trailing Whitespace

# Select the entire buffer with %
# Run:
:re \s+$ ""

# Or for all lines:
:re \s+$ "" /g

Converting Tabs to Spaces Within Selections

# Select the region
# Replace tabs with 4 spaces
:re \t "    "

Wrapping Text in Tags (HTML/XML)

# Select the text to wrap
:re (.+) 
\n$1\n
# Note: \n inserts a newline in the replacement # This wraps the selection in
tags

Best Practices

Edge Cases and Troubleshooting

Regex Escaping

Remember that Helix uses Rust's regex flavor. Characters like ., *, +, ?, [, ], (, ), {, }, ^, $, |, and \ have special meanings. Escape them with \ when you need literal matches, or use the /x flag.

# Replace literal parentheses (without /x):
:re \(.*\) "removed"

# With /x flag — cleaner:
:re /x (.*) "removed"

Newlines in Patterns and Replacements

To match across lines, use \n in your pattern. In replacements, \n inserts a newline. Note that by default, . does not match newlines — use (?s) for single-line mode or [\s\S] as a workaround.

# Replace two consecutive lines joined with a comma
:re (\w+),\n(\w+) $1 and $2

Zero-Length Matches

Helix handles zero-length matches (like \b or lookahead assertions) gracefully. However, replacing a zero-length match inserts text at that position without removing anything.

# Insert a comma at word boundaries (not removing anything)
:re \b ","

# This inserts commas between words — use carefully

Conclusion

Helix's find and replace system is a carefully integrated part of its selection-first editing model. By combining precise structural selections, incremental search, regex capture groups, interactive confirmation, and multi-file workflows, you can handle everything from quick local edits to complex project-wide refactorings without leaving the editor or reaching for external tools. The key insight is that Helix encourages you to see what you're changing before you change it — selections provide visual feedback, confirmation mode adds explicit approval, and structural boundaries keep replacements contained. Mastering find and replace in Helix means mastering the editor's selection primitives, and once you internalize that workflow, text manipulation becomes faster, safer, and more intuitive than in traditional editors that separate search from selection from action.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles