ripgrep (rg): Fast Code Search
What is ripgrep (rg)?
Conclusion: ripgrep is a blazing-fast grep alternative written in Rust.
rg patternsearches the current directory recursively and respects.gitignoreto skip noise. The binary is namedrg.
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 isripgrep)
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
.gitignoreand 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.debfrom GitHub Releases or usecargo 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 patternis the base form. Use-ito ignore case,-wto match whole words, and-Fto 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 TYPEfor a language/extension group, and-g 'glob'for an arbitrary pattern. Runrg --type-listto 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
--hiddenfor hidden files,-u(--unrestricted) to ignore.gitignore,-uufor both, and-uuuto 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:
-rpreviews the replaced output. It does not modify files (stdout only). To rewrite real files, combine it with something likesed -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 -rnforrgand 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'