ripgrep & fd — Modern File Search for Developers
In this tutorial, you'll learn about ripgrep & fd. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
ripgrep (rg) and fd are modern replacements for grep and find that search codebases and filesystems with dramatically better performance, smarter defaults, and developer-friendly features.
What You'll Learn
How to use ripgrep for blazing-fast code search through millions of files, use fd for intuitive file discovery with automatic .gitignore awareness, combine both tools with fzf and bat for interactive workflows, and integrate them into your editor and daily routine.
Why Modern Search Tools Matter
The classic Unix tools — grep -r and find — were designed in the 1970s. They are slow on modern codebases (thousands of files, node_modules, .git), ignore .gitignore by default, and lack features like colored output, context lines, and file type filtering. ripgrep searches 10-20x faster than grep while respecting --ignore rules automatically. fd finds files by name, extension, or type with a fraction of find's syntax. DodaZIP's codebase (1.2M lines across 400K files) uses ripgrep for all searches, completing typical queries in under 200ms.
Learning Path
flowchart LR A[Terminal Setup] --> B[Shell Scripting] B --> C[ripgrep & fd
You are here] C --> D[fzf & zoxide] C --> E[bat & delta] style C fill:#f90,color:#fff
ripgrep (rg) — Code Search
Installation
# macOS
brew install ripgrep
# Ubuntu/Debian
sudo apt install ripgrep
# Fedora
sudo dnf install ripgrep
# Arch
sudo pacman -S ripgrep
# Download binary
curl -LO https://github.com/BurntSushi/ripgrep/releases/download/14.1.0/ripgrep_14.1.0_amd64.deb
sudo dpkg -i ripgrep_14.1.0_amd64.deb
Basic Searching
# Simple search in current directory
rg "TODO"
# Case-insensitive
rg -i "function"
# Search specific file types
rg -t js "export default"
rg -t py "def __init__"
rg -t rs "impl"
# Search by glob pattern
rg "class" --glob "*.{ts,tsx}"
# Show only filenames (no matching lines)
rg -l "import React"
# Count matches per file
rg -c "function"
Expected output:
$ rg "TODO"
src/main.js:10: // TODO: implement error handling
src/utils.js:25: // TODO: add validation
src/api.js:8: // TODO: move to config
$ rg -c "function" src/
src/main.js:3
src/utils.js:12
src/api.js:5
Context and Formatting
# Show lines before and after matches
rg -C 3 "error" # 3 lines before and after
rg -B 5 "error" # 5 lines before
rg -A 5 "error" # 5 lines after
# Show line numbers
rg -n "pattern"
rg --no-line-number "pattern" # suppress line numbers
# Show only matching text (not entire line)
rg -o "https?://[^ ]+"
# Pretty output with colors
rg --color always "pattern"
# JSON output for programmatic use
rg --json "pattern" | jq 'select(.type == "match") | .data'
Advanced ripgrep
# Search hidden files and directories
rg -u "secret" # also search hidden files
rg -uu "secret" # search everything (including .gitignore)
rg -uuu "secret" # search all files including binary
# Fixed string search (no regex)
rg -F "std::cout <<"
# Show files without matches
rg -l "deprecated" | rg -v "vendor" # exclude vendor dirs
# Replace text (with sed)
rg "old_function" -l | xargs sed -i 's/old_function/new_function/g'
# Search and preview with fzf
rg -l "TODO" | fzf --preview 'bat --color=always {}'
# Search compressed files
rg -z "error" log.gz
# Multi-line search
rg -U 'import \{\n \w+,\n \w+\n}' src/
Performance Comparison
# Compare rg vs grep
hyperfine "grep -r 'function' src/" "rg 'function' src/"
Expected:
Benchmark 1: grep -r 'function' src/
Time (mean +- sd): 456.2 ms +- 12.3 ms
Benchmark 2: rg 'function' src/
Time (mean +- sd): 23.1 ms +- 1.2 ms
Summary
rg 'function' src/ ran 19.75 times faster than grep -r 'function' src/
fd — File Discovery
Installation
# macOS
brew install fd
# Ubuntu/Debian (package name differs)
sudo apt install fd-find
# The binary is named fdfind on Ubuntu; alias it
alias fd=fdfind
# Fedora
sudo dnf install fd-find
# Arch
sudo pacman -S fd
# Download binary
curl -LO https://github.com/sharkdp/fd/releases/download/v9.0.0/fd_9.0.0_amd64.deb
sudo dpkg -i fd_9.0.0_amd64.deb
Basic File Search
# Find files by name (partial match)
fd "config"
# Exact filename
fd "^config$"
# Find by extension
fd -e js
fd -e py -e rs
# Find directories
fd -t d "src"
# Find files only
fd -t f "test"
# Find symlinks
fd -t l "link"
# Hidden files
fd -H ".git"
fd -H ".env"
Expected output:
$ fd "config"
src/config.js
src/config.json
tests/config.test.js
deploy/config.yaml
Advanced fd
# Case-insensitive search
fd -i "readme"
# Exclude directories
fd "log" -E "node_modules" -E ".git" -E "vendor"
# Maximum search depth
fd "test" --max-depth 2
fd "config" --min-depth 3
# Search by file size
fd -s +100k # Files larger than 100KB
fd -s -1M # Files smaller than 1MB
fd -s +10M -e mp4 # Large video files
# Search by modification time
fd --changed-within 1hour "*.py"
fd --changed-before "2026-01-01" "*.log"
# Execute command on results
fd "*.js" -x wc -l {}
fd "*.jpg" -x cp {} /backup/
# Batch rename
fd "screenshot" -x mv {} "old-{}"
fd + ripgrep Integration
These tools are even more powerful together:
# Find all Python files and search within them
fd -e py | xargs rg "def handle_"
# Find files, preview with ripgrep search
fd -e json -x rg "api_key"
# Find and search excluding node_modules
fd -e js -E node_modules | rg "import"
# fzf integration: find then fuzzy filter
fd -t f | fzf --preview 'bat --color=always {}'
Integration with Editors
VS Code
// settings.json
{
"search.useParentIgnoreFiles": true,
"search.followSymlinks": false,
"search.exclude": {
"node_modules": true,
"vendor": true
}
}
Neovim (telescope)
-- Using ripgrep with telescope
require('telescope').setup {
defaults = {
vimgrep_arguments = {
"rg",
"--color=never",
"--no-heading",
"--with-filename",
"--line-number",
"--column",
"--smart-case",
},
},
}
Shell Aliases
# ~/.bashrc or ~/.zshrc
alias rg='rg --smart-case'
alias fdd='fd -t d' # Find directories
alias fdf='fd -t f' # Find files
alias search='rg -C 3' # Search with context
alias count='rg -c' # Count matches
Common Errors
1. ripgrep Shows No Results for Obvious Patterns
ripgrep respects .gitignore by default. If files match ignore rules, they are skipped. Use rg -u or rg --no-ignore to override.
2. "fd: command not found" on Ubuntu
The package is fd-find and the binary is fdfind. Install fd-find and create an alias: alias fd=fdfind.
3. ripgrep Searches Binary Files and Shows Garbage
ripgrep skips binary files by default. If binary output appears, use rg --no-ignore and -u flags carefully. Use rg -t to restrict to text file types.
4. fd Ignores Hidden Files When Needed
fd hides dotfiles by default. Use fd -H to include hidden files and . directories.
5. Performance Still Slow on Repos With No .gitignore
Create a .gitignore file or use -E to exclude known large directories like node_modules, vendor, and .git.
6. rg --json Produces Too Much Output
Pipe to jq: rg --json pattern | jq 'select(.type=="match") | .data.path.text'. The JSON format includes summary and end messages; filter with jq for specific data.
7. fd --exec Hangs on Large Result Sets
fd waits for each -x command to complete before spawning the next. For large sets, use -X (batch mode) instead: fd -e js -X rm.
Practice Questions
1. What flag makes ripgrep search case-insensitively?
-i or --ignore-case. ripgrep also supports --smart-case that switches to case-insensitive when the pattern is all lowercase.
2. How do you find all Python files modified in the last hour with fd?
fd -e py --changed-within 1hour
3. How does ripgrep handle .gitignore by default?
It respects .gitignore rules and skips ignored files. Use -u or --no-ignore to search everything.
4. What command finds files by type (directory, file, symlink) with fd?
Use -t d for directories, -t f for files, -t l for symlinks.
5. How do you count the number of matches per file with ripgrep?
rg -c "pattern" prints each matching filename with its match count.
Challenge: Create a Shell Script that audits your largest project. Use fd to count files by extension (sorted by count), ripgrep to find all TODOs, FIXMEs, and HACKs, then combine results into a markdown report. The report should show file counts, TODO density (TODOs per file), and the top 10 most changed files using fd with --exec git log --oneline.
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-24.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro