Skip to content

ripgrep & fd — Modern File Search for Developers

DodaTech Updated 2026-06-24 8 min read

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

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
# 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.

Is ripgrep available on Windows?

Yes — ripgrep has native Windows binaries on GitHub releases. It also works through WSL.

Can I use ripgrep as a grep replacement globally?

Add alias grep=rg to your shell config. Most grep flags work the same, but ripgrep adds many more features.

Does fd work with fzf for interactive file finding?

Yes — fd -t f | fzf is the fastest way to interactively find files. Many developers use this instead of fuzzy finder plugins.

How does ripgrep handle very large files?

ripgrep is memory-mapped and can search multi-GB files. It uses Boyer-Moore-style search for literal patterns and is optimized for large inputs.

Can I use ripgrep to search inside PDFs or Office documents?

Not directly — those require text extraction first. Use pdftotext with ripgrep, or tools like pdfgrep.

What's Next

fzf & zoxide — Fuzzy Finder & Directory Jump
bat & delta — Better cat & Diff
Lazygit — Terminal Git UI Guide

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