Searching files from the command line on macOS: mdfind, fd, and friends
Finder's search is slow. Spotlight's is noisy. When you actually need to find a file on macOS — by name, by content, by metadata — the command line is faster and more honest. This post walks through every tool worth knowing in 2026, with t…
Finder's search is slow. Spotlight's is noisy. When you actually need to find a file on macOS — by name, by content, by metadata — the command line is faster and more honest. This post walks through every tool worth knowing in 2026, with the trade-offs that matter to developers.
If you skim: use fd for filename search in a code tree, ripgrep for content search, and mdfind when you need to query Spotlight's metadata for files outside your repo. The rest of this post explains when each is the right pick.
The five tools
There are five command-line file searchers on macOS that earn their place in 2026:
mdfind— Apple's CLI front-end to the Spotlight index.fd— Rust filename search that respects.gitignore.ripgrep(rg) — Rust content search, also.gitignore-aware.find— the BSD tool, slow but always available.locate— older UNIX file index, occasionally useful.
Each is a different shape. mdfind queries an existing OS-level index. fd walks the filesystem each time. ripgrep reads file contents. find is the historical default. locate is a niche backup.
mdfind — when Spotlight's index is the right answer
mdfind queries the same index Spotlight does, but from the shell. It is the right tool when:
- You want to find a file by metadata (kind, author, recently modified).
- The file is outside your code tree — Documents, Downloads, Desktop.
- You want results to match Spotlight's GUI exactly.
Basic usage:
# Filename match anywhere on the indexed disk
mdfind useEffect.test.ts
# Limit to a folder
mdfind -onlyin ~/Documents 'invoice 2025'
# Files of a specific kind
mdfind 'kMDItemContentTypeTree == "public.image"' -onlyin ~/Desktop
# Recently modified PDFs
mdfind 'kMDItemContentTypeTree == "com.adobe.pdf" && kMDItemFSContentChangeDate >= $time.today(-7)'
The strength of mdfind is that the index is already built — queries return in milliseconds. The weakness is that the index is Spotlight's index, which means it includes folders you may not want indexed (Mail attachments, iCloud caches) and excludes folders you actively excluded (node_modules, your dev tree if you turned it off).
For developers, mdfind is the right tool for finding non-code artifacts. It is the wrong tool for finding files in ~/code, both because the index drifts and because the ranking is not yours to control.
fd — the right tool for code
fd is a Rust replacement for find that does the right thing by default. Install:
brew install fd
Why it is the right tool for code:
- Respects
.gitignore. Out of the box it skipsnode_modules,.next,dist,target, and every other build artifact directory you already told git to ignore. - Fast. Walking 100,000 files takes well under a second on an SSD.
- Sensible syntax. Pattern is a regex unless it isn't, paths are paths, no nonsense.
Daily usage:
# Find by name (regex)
fd 'useEffect.*\.test\.ts$'
# Find in a specific directory
fd -t f 'config' ~/code
# Find directories
fd -t d node_modules ~/code
# Include hidden, ignore .gitignore (when you want everything)
fd -HI '\.env'
# Run a command on each result
fd -e ts -x prettier --write
The first time you use fd on a busy repo and it returns instantly with exactly the file you wanted, the tool sells itself. Most developers stop using find within a week.
ripgrep — content search
ripgrep is the same idea as fd but for file contents. Install:
brew install ripgrep
Basic usage:
# Search for a string in the current directory tree
rg "useEffect"
# Limit to a file type
rg "useEffect" -t ts
# Case-insensitive
rg -i "TODO"
# Show only filenames
rg -l "createMcpServer"
# Search with a regex, multiline mode
rg -U 'export function .*\([^)]*\) \{'
ripgrep respects .gitignore by default. On a large repo it is 10-50x faster than grep -r for the same query, and the output formatting (filename, line number, match) is what every modern editor's quick-fix list expects.
If your team's onboarding doc says "use grep," update the doc.
find — the BSD default
find is the POSIX tool. Every macOS install has it, every CI runner has it, every Linux server has it. Its strength is universality; its weakness is syntax.
The cases where find is still the right answer:
- You are writing a shell script that must work on a minimal environment.
- You need an operation
fddoes not support (e.g., compound predicates with-newerand-prune). - You are debugging a build system that calls
findand you need to match its behavior exactly.
A few find idioms that are still useful:
# Find files modified in the last 24 hours
find . -type f -mtime -1
# Find files larger than 100 MB
find . -type f -size +100M
# Find and delete .DS_Store files
find . -name '.DS_Store' -delete
# Find empty directories
find . -type d -empty
For everything else, fd is faster to type and faster to run.
locate — the UNIX index
locate is a different file index from Spotlight's, built by a cron job (updatedb). On macOS it exists but is not enabled by default. To turn it on:
sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist
Then queries are fast:
locate useEffect
The catch: the index updates on a schedule (typically daily), so files created today may not be in it. For most developers, mdfind covers the same use case with a more up-to-date index. locate is mostly useful when you want a search index that is independent of Spotlight — for example, in a script that must not depend on Spotlight being healthy after a macOS update.
A decision tree
For a developer in 2026:
- Find a file by name in a code tree →
fd. - Find a string in a code tree →
rg. - Find a recently modified personal file →
mdfindor your launcher's file search. - Find by metadata (kind, size, age) →
mdfindfor indexed,findfor not. - Shell script for CI →
find, for portability. - Spotlight is broken after a macOS update →
fdandrgkeep working;locateis a fallback for non-code search.
Two of the five tools (fd, rg) cover 90% of daily developer file search. The other three are situational.
Wire them into your editor and launcher
The reason fd and rg matter is not the standalone CLI — it is that every modern editor uses them under the hood. VS Code's file picker calls rg when available. Zed's project search is rg. Neovim's Telescope plugin defaults to fd and rg. Your launcher's "find file" command, on CmdSpace and Raycast, can be configured to call fd for filename and rg for content.
The practical implication: install these two tools once and every keyboard-driven search surface on your Mac gets faster. There is no separate "make my editor faster" project — they share the same backend.
If you spend your day in a launcher, see A Mac terminal launcher workflow for how to wire shell commands so file search results open in your editor with one keystroke.
What you can skip
A few tools you may see recommended that are not worth your time in 2026:
ack— the ripgrep predecessor, slower and less maintained.ag(the Silver Searcher) — same; ripgrep is faster and the project is more active.grep -randfind -exec grep— slow on large repos, do not respect.gitignorewithout effort.
Move on.
Spotlight is not your friend here
The natural question is: why not just use Spotlight's GUI for file search? The answer is the same as in Why Spotlight is hostile to developers: Spotlight's ranking is tuned for non-developer search, its index includes folders you do not want, and its results are below the fold for code anyway.
The CLI tools above give you control: you decide what to index (via .gitignore), what to search (filename or content), and how to run the result (open in editor, pipe to another command). Spotlight gives you none of that.
Try it for a week
If you have never run fd or rg daily, install them today and use them exclusively for one week. By Friday you will have stopped reaching for the Finder search bar, and the time you save on each lookup compounds across the dozens of file searches a developer does in a day.
brew install fd ripgrep
Two commands. Permanent upgrade.