Searching a Codebase Without Opening a Single File
When you need to find every place a function, variable, or config key is referenced across hundreds or thousands of files, opening each one manually is not an option. grep ("global regular expression print") reads through files line by line and prints every line matching a pattern, and it does this fast enough to scan an entire repository in well under a second.
The Basic Recursive Search
The core command you will use most often is:
grep -rn "connectToDatabase" .
-rsearches recursively through subdirectories-nprints the line number of each match"connectToDatabase"is the text to search for.tells grep to start from the current directory
Output looks like this, with the file path and line number prefixed to each match:
./src/db/pool.js:12:function connectToDatabase(config) {
./src/api/users.js:4:const { connectToDatabase } = require('../db/pool');
./tests/db.test.js:8: connectToDatabase(testConfig);
Case-Insensitive and Whole-Word Matching
Add -i to ignore case, useful when you are not sure whether a symbol was written in camelCase, PascalCase, or all lowercase somewhere:
grep -rni "connecttodatabase" .
Add -w to match only whole words, which prevents grep -rn "log" from also matching catalog, login, or logger:
grep -rnw "log" .
Filtering by File Type
In a large repository you usually do not want matches from node_modules, build artifacts, or binary files. GNU grep's --include and --exclude-dir flags scope the search:
grep -rn --include="*.js" --exclude-dir={node_modules,dist,.git} "connectToDatabase" .
This searches only .js files while skipping the three noisy directories entirely, which both speeds up the search and cleans up the output.
Regular Expressions for Real Patterns
grep supports regex out of the box. Use -E for extended regex syntax, which lets you use +, ?, and | without backslash-escaping them:
grep -rnE "function\s+(get|set)User" .
This finds any line containing function getUser or function setUser, regardless of how many spaces separate the keyword from the name. Combine with -o to print only the matched text instead of the whole line, handy for extracting values rather than reading context:
grep -rnoE "API_KEY=[A-Za-z0-9]+" .env.example
Showing Context Around a Match
A bare match with no surrounding code can be hard to interpret. Use -A (after), -B (before), or -C (both) followed by a number of lines:
grep -rn -C 3 "TODO: remove before release" .
This prints three lines of context above and below every match, giving you enough surrounding code to understand it without opening the file.
When You Need Even More Speed: ripgrep
On a codebase with tens of thousands of files, standard grep can feel sluggish, mostly because it does not know which directories to skip without you telling it explicitly. ripgrep (the rg command) solves this by respecting .gitignore automatically and using a faster regex engine by default. Install it with your package manager:
# macOS
brew install ripgrep
# Debian/Ubuntu
sudo apt install ripgrep
# Windows (via winget)
winget install BurntSushi.ripgrep.MSVC
The equivalent search is shorter because ripgrep is recursive and respects .gitignore by default:
rg "connectToDatabase"
No -r flag needed, no manual exclusion of node_modules — ripgrep already skips anything ignored by git. It also prints file paths and line numbers by default, and typically runs several times faster than grep on large trees because it uses multiple threads and a more efficient underlying regex engine.
-i, -w, -A/-B/-C, -o), so muscle memory from grep transfers directly. Add --type js or --type py to restrict a search to a specific language without writing out glob patterns.Combining grep With Other Commands
grep pairs naturally with other CLI tools through pipes. To count how many files contain a match:
grep -rl "deprecated" . | wc -l
-l lists matching filenames only (no line content), and piping to wc -l counts the lines, giving you a quick tally. To search only files already tracked by git, skipping anything ignored:
git grep -n "connectToDatabase"
git grep is often the fastest option inside a git repository since it is git-aware and automatically excludes ignored files without any extra flags.
Discussion & Insights