Making file search on a Mac fast again
Some searches on a Mac return before the typing stops. Others spin for a minute and come back with nothing, on the same machine, for a file that definitely exists. Anyone trying to find any file mac side eventually runs into this split, and it is not about how fast the hardware is. Two entirely different search engines live on the same system. One queries an index that was built in advance. The other walks the file system and compares entries one at a time. Almost every complaint about slow search, and every complaint about search missing a file, comes down to which of the two is running and whether it was pointed at the right place.
Two engines, two failure modes
Spotlight, Finder search, and the mdfind command all query the same metadata index. The index holds names, types, creation and modification dates, and for supported formats the text content of the file. Nothing is read from disk at query time, which is why results arrive while a query is still being typed. Apple describes the behaviour of the front end plainly:
Spotlight lists top matches first; click a top match to preview or open it. Spotlight also suggests variations of your search; those results appear in Spotlight or on the web. Source: support.apple.com
Ranking and suggesting are the giveaway. This is an answer box, not an exhaustive file listing. It is fast because it never touches the file system, and it is incomplete for the same reason.
The other engine is a directory scan: find, grep, and the standalone search utilities that deliberately avoid the index, such as EasyFind and Find Any File. These start at a given directory and walk everything beneath it, checking each entry. Results are always current, hidden and system files are visible, and nothing can be missing because nothing was pre-filtered. The cost is time, and that time scales with the number of entries walked, not with the size of the answer.
So the useful question when a search feels slow is never whether the Mac is slow. It is which engine is running, and if it is a scan, whether it is walking far more of the disk than the question requires.
| Index query | Directory scan | |
|---|---|---|
| Tools | Spotlight, Finder search, mdfind |
find, fd, grep, rg, standalone scanners |
| Speed driver | Size of the result, not the disk | Number of entries walked |
| Sees hidden and system files | No | Yes |
| Sees files excluded from indexing | No | Yes |
| Current at the moment of the query | Depends on index freshness | Always |
Query the index directly instead of through Spotlight
The Spotlight field mixes files with apps, mail, contacts, calculations, and web suggestions, then shows a handful of files below all of that. For file work, querying the same index from a terminal is both faster to narrow and easier to reuse. That is what mdfind does.
mdfind -name invoicereturns items whose name contains the word, straight from the index.mdfind -onlyin ~/Documents contractrestricts the query to a directory tree while still using the index.mdfind "kMDItemContentType == 'com.adobe.pdf'"filters on a metadata attribute rather than a name.- A bare word matches indexed text content as well as names, so
mdfind quarterlyreaches inside documents.
None of these walk the disk, so scoping to the whole home folder costs roughly the same as scoping to one directory. The reason to scope anyway is precision, not speed.
For Finder search, one setting is worth changing before anything else. In Finder settings, Advanced tab, set search to begin in the current folder. The default begins every search across the entire Mac, which turns what was meant as a narrowing action into a whole disk question. It stays fast, because it is still an index query, but the result list is longer than it needs to be and the target takes more scrolling to reach.
When a scan is unavoidable, cut the tree first
Some files are simply not in the index. Anything inside a folder whose name ends in .noindex, anything under a location listed in Spotlight's Search Privacy settings, most hidden files, and the contents of archives that have never been expanded. For those, a scan is the only option, and the only way to make a scan fast is to walk fewer entries.
There are three ways to do that, and they compose:
- Start deeper.
find ~/Projects -name "*.csv"instead of starting at the home folder. Most searches have a plausible subtree, and starting there removes the majority of entries immediately. - Limit depth.
find . -maxdepth 3 -name "*.log"stops the walk after three levels. Configuration files and top level artifacts are shallow by nature, so this cuts deep dependency trees out of the question entirely. - Prune branches.
find . -name node_modules -prune -o -name "*.ts" -printskips the subtree instead of descending into it. Dependency directories and build output often hold most of the entries on a disk while almost never holding the target.
Changing tools helps too. Both fd and rg walk in parallel across several threads, so the same subtree finishes sooner than it would under find or grep. Their defaults differ in one important way: both skip hidden files and anything matched by a .gitignore unless told otherwise. Passing -uu to rg, or -HI to fd, turns those exclusions off. Outside a source repository, that default is the single most common reason a fast search appears to miss a file that grep -r finds.
macOS also ships locate, which queries a database built by a periodic job rather than walking the disk. If that job has never run, the command reports that the database is too small and returns nothing useful, which is the state most machines are in.
There is one more way to avoid repeating an expensive scan: stop re-running it. A search that gets typed more than twice belongs in a shell function or an alias with the scope, the prune list, and the flags already set. A Finder search that gets rebuilt more than twice belongs in a Smart Folder, which stores the criteria and re-runs them on open. Neither makes an individual query faster, and both remove the part of the cost that comes from reconstructing the question every time.
Check the index before rebuilding it
When an index query returns nothing, rebuilding the index is the common reflex and usually the wrong first move. Four checks come first, and all of them take seconds:
mdutil -s /reports whether indexing is enabled for that volume. If it is off, that alone explains empty results.- The Search Privacy list in System Settings under Spotlight excludes whole folders and disks from results. Items added there years ago are easy to forget.
- A folder whose name ends in
.noindexis skipped, and duplicating such a folder carries the suffix along. - An external disk connected recently is still being indexed in the background, and results from it stay incomplete until that finishes.
Only after those does sudo mdutil -E / make sense. It erases and rebuilds the index for a volume, the work runs in the background, and on a large disk with many documents it can take from tens of minutes to several hours. Search results are incomplete for the entire duration, so running it against a problem that was actually a privacy list entry costs hours and fixes nothing.
Names and contents are different searches
Searching inside files splits along the same line as searching for them. Passing a bare word to mdfind reads indexed text content and returns immediately, but only for formats the importers understand: plain text, most PDFs, and the common document formats.
grep and rg open files and read them. Format does not matter, files outside the index are reachable, and the time taken scales with the volume of bytes read. When rg searchterm takes a few seconds inside a large repository, that is the disk being read, not the tool being inefficient.
The practical split is straightforward. For document contents, query the index. For code, logs, and configuration files, scan. Documents are usually in formats the index understands and in locations it covers. Code and logs are usually in locations that hidden file rules and ignore files keep out of it.
When scanning contents, cut the volume of bytes before cutting anything else. Restricting file types with rg pattern --glob "*.ts", or excluding oversized files with --max-filesize 1M, reduces what actually gets read rather than what gets reported. A single multi-gigabyte log file in the tree accounts for most of the wait on its own, so excluding it by size often matters more than the directory scope. Compressed archives and disk images are outside both engines until they are expanded or mounted.
Network shares and external disks change the arithmetic
A network share behaves differently from local storage. If the server does not support the search protocol the Mac expects, there is no index to query, and the search becomes a scan performed over the network. Every directory listing becomes a round trip, so the same number of entries takes far longer than it would locally.
Two options are usually faster than waiting. Keep the subset of material that gets searched often on local storage, or use the search function the server itself provides, since it can search its own storage without sending every listing across the link. External disks are less severe but have their own trap: an index that was interrupted by an unplanned disconnect can stay partially built, and the volume then returns incomplete results indefinitely while appearing perfectly normal.
The expensive part is what happens after the result appears
Fixing scope and tool choice takes real time out of the search itself. The whole workflow often still feels slow, because the time is not going into the search.
Count one cycle. A Finder search returns the file. Acting on it from a shell means selecting it, copying the path, switching windows, and pasting. Going the other way, a path found on the command line has to be carried back to a window to be looked at. Each pass costs a few seconds and happens dozens of times a day, which is how it comes to outweigh the search time entirely. A file manager with a built-in terminal removes that specific step by keeping the visible folder and the shell's working directory identical, and the Features page describes what that arrangement covers. For how it differs from dual pane managers and terminal-first tools, which are aimed at different problems, see Compared with other file managers. Details about supported systems and limits are collected in the FAQ.
What to change first
Set Finder search to start in the current folder, then run mdutil -s / and read the Search Privacy list once. Those three take five minutes and account for most of what looks like slow or broken search. If the friction that remains is the switch between the result and the command that acts on it, that is a layout problem rather than a search problem, and Atriens is built around that gap.
Frequently asked questions
Why is Spotlight instant while `find` takes a minute?
They work in opposite ways. Spotlight queries a metadata index built in advance, so the response time barely changes as the number of files grows. find starts at a directory and walks everything below it, checking each entry, so its time scales with how many entries it walks. Starting deeper in the tree, adding -maxdepth, or pruning dependency directories all cut that number directly.
When should `mdfind` be used instead of `find`?
Use mdfind when the target is something the index knows: a name, a file type, a date, or text inside a supported document format. It answers immediately and accepts -onlyin to restrict the scope. Use find when the target sits outside the index, which covers hidden files, folders ending in .noindex, and anything under a path in the Search Privacy list.
Why do `fd` and `rg` miss files that `grep -r` finds?
Both skip hidden files and anything excluded by a .gitignore unless flags are added. Passing -uu to rg or -HI to fd disables those defaults. Inside a source repository the behaviour is helpful, and outside one it is the most common cause of a search that appears to be missing files.
Searching a network share is extremely slow. What can be done?
If the server does not support the search protocol, the Mac cannot query an index and has to scan over the network, turning every directory listing into a round trip. Keeping frequently searched material on local storage, or using the search feature the server provides, avoids the round trips. Indexing a mounted share locally is not an option the system offers.