ripgrep (rg): Fast Code Search

ripgrep (rg): Fast Code Search

What is ripgrep (rg)?

Conclusion: ripgrep is a blazing-fast grep alternative written in Rust. rg pattern searches the current directory recursively and respects .gitignore to skip noise. The binary is named rg.

ripgrep was built for searching across code bases. The "search a whole directory" task you used to spell out as grep -rn becomes the default behavior, no extra flags required.

The first line to memorize

rg TODO

This searches the current directory recursively and automatically skips .git/ and build artifacts (anything listed in .gitignore).

Assumptions (target environment)

  • OS: Ubuntu / Debian family (package names are nearly identical on other distros)
  • The binary is rg (the package is ripgrep)

Why is it faster than grep?

Conclusion: Three things add up: Rust's fast regex engine, parallel searching across files, and shrinking the search set up front via .gitignore and binary detection.

The main reason is not the implementation language alone — it is that ripgrep searches fewer files. grep -r dutifully walks .git/ and node_modules/, while ripgrep excludes them from the candidate set in the first place.

Feature grep ripgrep
Recursive search needs -r default
Respects .gitignore no yes (default)
Binary files scanned skipped automatically
Parallelism none yes
Line numbers needs -n default on a terminal

The value in practice is not only "fast" but "clean output by default." Results are not buried in noise.

How do I install it?

Conclusion: On Ubuntu/Debian use apt install ripgrep. If the packaged version is old, grab the .deb from GitHub Releases or use cargo install ripgrep.

# Ubuntu / Debian
sudo apt install ripgrep

# Fedora / RHEL family
sudo dnf install ripgrep

# macOS (Homebrew)
brew install ripgrep

# If you have a Rust toolchain
cargo install ripgrep

Verify the install:

rg --version
ripgrep 14.1.0
-SIMD -AVX (compiled)
+SIMD +AVX (runtime)

The apt version on old Ubuntu (e.g. 18.04) is dated and ships fewer -t types. For the latest features, prefer the .deb from GitHub Releases.

How do I run a basic search?

Conclusion: rg pattern is the base form. Use -i to ignore case, -w to match whole words, and -F to search a fixed string (disabling regex).

# Search the current tree for "config"
rg config

# Ignore case
rg -i config

# Whole word ("configure" will not match)
rg -w config

# Treat as a literal string, not a regex
rg -F "a.b.c"

By default results show the file name, line number, and the matching line, all colorized.

src/main.rs
12:    let config = load_config();
48:    config.reload();

rg -F is handy when you want to find a string containing . or * (version numbers, regex examples) literally. No escaping required.

How do I filter by file type?

Conclusion: Use -t TYPE for a language/extension group, and -g 'glob' for an arbitrary pattern. Run rg --type-list to see the available types.

# Search Python files only
rg -t py "import requests"

# Exclude JavaScript / TypeScript
rg -T js "function"

# Target an extension directly with a glob
rg -g '*.md' "TODO"

# Multiple globs (! excludes)
rg -g '*.rs' -g '!target/*' "unsafe"

List the available types:

rg --type-list | head
agda: *.agda, *.lagda
asciidoc: *.adoc, *.asc, *.asciidoc
asm: *.S, *.a51, *.asm, *.s
...

Lowercase -t means "include", uppercase -T means "exclude". Mnemonic: T for exclude (it negates the type).

How do I show lines around a match?

Conclusion: Use -A N (after), -B N (before), and -C N (both) to print context lines. Essential when reading around an error in logs.

# Also show 3 lines after the match
rg -A 3 "panic"

# Also show 2 lines before the match
rg -B 2 "Exception"

# 3 lines on each side (the one you use most)
rg -C 3 "Traceback"

Other output controls:

# Only the names of matching files (when you want a list)
rg -l "deprecated"

# Just the match count
rg -c "TODO"

# Extract only the matched portion
rg -o 'https?://[^ ]+'

rg -l pattern | xargs ... is powerful: pass only the hit files to a follow-up command.

I want to search files ignored by .gitignore

Conclusion: Use --hidden for hidden files, -u (--unrestricted) to ignore .gitignore, -uu for both, and -uuu to search everything including binaries.

ripgrep defaults to a "clean" search, but sometimes you need to look inside logs, .env, or node_modules. Peel back the filters in stages.

# Include hidden files (.env, etc.)
rg --hidden "API_KEY"

# Ignore .gitignore (search node_modules and friends)
rg -u "lodash"

# Hidden files + ignore .gitignore
rg -uu "TODO"

# Everything, including binaries
rg -uuu "magic_bytes"

-uuu scans the contents of .git/ and binaries, so it is slower and noisier. The rule of thumb: start with the default, then add one -u at a time only as needed.

Can it replace text?

Conclusion: -r previews the replaced output. It does not modify files (stdout only). To rewrite real files, combine it with something like sed -i.

# Show the result of replacing foo with bar (files unchanged)
rg 'foo' -r 'bar'

# Replacement preview using capture groups
rg '(\w+)@(\w+)' -r '$2.$1'

rg -r is for confirmation only. The safe pattern is to review the result, then rewrite with sed.

# Confirm targets and replacements with rg first, then
sed -i 's/foo/bar/g' $(rg -l 'foo')

sed -i is a destructive operation. Always confirm the list of hit files with rg -l before running it.

Quick reference for switching from grep

Conclusion: In most cases you can swap grep -rn for rg and it just works. Learn type filtering and context display and your daily searches live entirely in ripgrep.

What you want grep ripgrep
Recursive directory search grep -rn pat . rg pat
Ignore case grep -i pat rg -i pat
Fixed-string search grep -F str rg -F str
File names only grep -rl pat . rg -l pat
Filter by extension grep -r --include='*.py' rg -t py pat
Surrounding context grep -C 3 pat rg -C 3 pat

Copy-paste: patterns you will use a lot

# List every TODO across the project
rg -n 'TODO|FIXME'

# Find error sites in Python only, with context
rg -t py -C 3 'raise '

# Check for leaked secrets, including hidden files
rg --hidden -g '!.git/*' 'API_KEY|SECRET'

Next Reading