find and locate both answer "where is that file", but they work in opposite ways. find walks the live filesystem on every run: it opens directories, reads entries, and tests each one against your expression. The result is always current, but on a large tree it can take seconds to minutes. locate skips the walk entirely. It queries a database that was built earlier by updatedb, so a query returns in milliseconds, but the answer is only as fresh as the last database build (typically a once-a-day cron job).
That tradeoff (live walk versus prebuilt index) is the whole decision. If you need a file created five minutes ago, or you need to filter by size, time, or permission, find is the only correct tool. If you just want to recall where nginx.conf lives on a huge box and you will run the query a few times, locate or its modern replacement plocate is far faster. This page is the comparison I reach for when deciding which one to type.
Set your values
Set your OS and the file you are searching for. Every command below updates with your values.
The core distinction
find is a filesystem crawler. Every invocation re-reads the directory tree from disk. Nothing is cached between runs. That is why find always reflects the current state of the disk, including files created one second ago, and why a find / on a server with millions of inodes is slow.
locate is a database client. The database is a compact, sorted list of every path on the system, generated by a separate program called updatedb. A locate query is a substring (or glob) match against that list. No directory is opened, no inode is read. The cost is freshness: any file created, moved, or deleted since the last updatedb run is invisible (or wrongly listed) until the database is rebuilt.
# find: walks the live filesystem now
find / -name ':search_term' -type f 2>/dev/null
# locate: queries the prebuilt database (instant)
locate :search_termThe 2>/dev/null on the find command discards permission-denied noise from directories you cannot read. locate has no such noise because it never touches the filesystem.
The locate family: GNU locate, slocate, mlocate, plocate
"locate" is not one program. It is a lineage of implementations, and which one you have depends on your distro and its age.
- GNU
locate(part offindutils) is the original. Its database stores every path it indexed, so any user querying it could see filenames anywhere on the system, including paths inside directories they have no permission to read. That is an information leak. slocate("secure locate") was the first fix. It stored permission data alongside paths and filtered results so a user only saw files they could actually reach. It is largely historical now.mlocate("merge locate") became the long-time default on most Linux distros. It is permission-aware likeslocate, and itsupdatedbis efficient because it reuses the existing database and only re-stats directories whose timestamps changed ("merging" the old index with filesystem changes). For most of the 2010s,mlocatewas simply whatlocatemeant on Debian, Ubuntu, Fedora, and RHEL.plocate("posix locate", or practically "fast locate") is the modern replacement. It uses a compressed posting-list index and is dramatically faster on large databases, often returning results beforemlocatehas finished reading its database file. It is permission-aware.plocateis the default on Debian 12 and later and Ubuntu 23.04 and later, where thelocatecommand now points at it.
On a current Debian or Ubuntu box, locate is almost certainly plocate. On older or RHEL-family systems it is usually mlocate. Run locate --version (or check what which locate resolves to) if you need to know for sure. The query syntax is the same across all of them, so scripts written for mlocate keep working under plocate.
find vs locate vs plocate compared
| Property | find | locate / mlocate | plocate |
|---|---|---|---|
| Freshness | Always current | Stale until next updatedb | Stale until next updatedb |
| Speed on large trees | Slow (full walk) | Fast | Very fast |
| Searches | Name, type, size, time, perms, content via -exec | Path name only | Path name only |
| Searches file content | Only via -exec grep | No | No |
| Permission-aware | Yes (sees what the calling user sees) | Yes (mlocate/slocate); GNU locate no | Yes |
| Needs a prebuilt database | No | Yes | Yes |
| Can filter by size / time / perm | Yes | No | No |
| Can run a command on matches | Yes (-exec, -delete) | No (pipe to xargs) | No (pipe to xargs) |
| Default on modern Debian/Ubuntu | Always present | Pre-2023 | Debian 12+, Ubuntu 23.04+ |
The shape of the table is the decision: find is the everything tool that pays for it in speed; the locate family trades freshness and filtering for near-instant name lookups.
updatedb: how the locate database stays current
locate is only useful because something keeps its database fresh. That something is updatedb, which walks the filesystem (slowly, like find) and writes the index. On a default install it runs once a day from cron or a systemd timer:
- Debian/Ubuntu
mlocate/plocate: a daily job under/etc/cron.daily/(or aplocate-updatedb.timersystemd unit on newer systems). - RHEL/Fedora
mlocate:/etc/cron.daily/mlocate.
The config file (/etc/updatedb.conf) controls what gets indexed: PRUNEPATHS excludes directories like /tmp and /var/spool, and PRUNEFS excludes filesystem types like nfs, proc, and sysfs. If locate cannot find something you know exists, check that file before assuming the database is broken.
When you need the database current right now (you just installed a package, or created a file you want locate to see), rebuild it by hand:
# Rebuild the locate database now (needs root)
sudo updatedb
# Then the query sees freshly-created files
locate :search_termupdatedb is itself a full filesystem walk, so running it is exactly as slow as the find you were trying to avoid. The win is amortization: you pay the walk once per day, then every locate query that day is free.
macOS: locate exists, but mdfind is the real tool
macOS ships a locate command (it descends from the BSD original), but the database is not built by default. A fresh locate query on macOS returns "locate: database too small" or nothing at all until you build it once with sudo /usr/libexec/locate.updatedb. After that, a locate.updatedb LaunchDaemon keeps it refreshed on a weekly-ish schedule, not daily.
In practice, on macOS I do not use locate at all. macOS has Spotlight, and Spotlight's command-line interface is mdfind. It queries the Spotlight metadata index, which the OS keeps continuously up to date as files change, so it has none of locate's staleness problem, and it can search file content and metadata, not just names.
# Linux has no mdfind; locate or plocate is the fast-search tool
locate :search_termSo the macOS hierarchy is: mdfind for fast interactive search, find for precise filtering and scripts, and locate only if you specifically want the BSD locate behavior and have built its database.
When to use find
Reach for find when correctness matters more than speed, or when you need anything beyond a name match:
- Filtering by size, time, or permission.
locateonly matches path names.find /var/log -size +100M -mtime +7has nolocateequivalent. - Acting on matches.
find ... -execandfind ... -deleterun commands on results.locatecan only print paths (you would pipe toxargs, which is fine, but the filtering still has to be a name match). - Freshly-created files. Anything created since the last
updatedbis invisible tolocate.findsees it immediately. - Scripts that must be exact. A cron job, a deploy hook, or a cleanup script cannot tolerate a stale index. Use
findso the result reflects the disk at the moment the script runs. - Searching file content.
locateindexes names only. To search inside files you needfind ... -exec grepor, better, find + grep together.
If the task involves the words "size", "modified", "older than", "owned by", "delete", or "and then run", it is a find job.
When to use locate or plocate
Reach for locate/plocate when you are doing interactive recall and speed is the point:
- "Where is that file" lookups by name. You know the filename, you do not know the path, and you want the answer now.
locate nginx.confbeatsfind / -name nginx.confby orders of magnitude. - Repeated queries. If you will run several name searches in a session, the prebuilt index pays off every time. The
findwalk would repeat the full disk read on each run. - Huge filesystems. On a box with tens of millions of files, a
find /walk can take minutes.locateanswers from the index regardless of tree size. - You are fine with day-old data. System binaries, config files, and installed packages do not move often. For those, the daily
updatedbcadence is plenty fresh.
The mental model: locate is for "I know roughly what it is called, remind me where it lives." If that describes the task, and the file is not brand new, locate wins.
When to use neither
Sometimes the right answer is a different tool entirely:
- macOS interactive search:
mdfind(covered above). Always current, searches content, no database to maintain. - Modern interactive
find:fdis a Rust-basedfindalternative with much friendlier defaults.fd nginxis a recursive, case-smart, regex search with no-nameboilerplate. It respects.gitignoreby default (great inside repos, occasionally surprising), uses colored output, and runs in parallel so it is fast even though it walks the live tree. For day-to-day "find me this file" at the terminal,fdis the one I actually type. It does not replacefindin scripts (the flag set is different andfindis universally present), but for interactive use it is the better experience. - Content search: if you are searching for a string inside files, not for a filename, use
ripgrep(rg). It is built for recursively grepping a tree and is far faster thanfind ... -exec grep. See the find + grep page for when to combine the two.
fd install is a one-liner: apt install fd-find on Debian/Ubuntu (the binary is fdfind there due to a name clash), brew install fd on macOS, cargo install fd-find anywhere with Rust.
Common mistakes
1. Trusting a stale locate database. The classic trap: locate prints a path, you cd to it, and the file is not there because it was deleted after the last updatedb. Or worse, locate misses a file that exists. If the result has to be accurate, either run sudo updatedb first or use find.
2. Expecting locate to find files created today. A file you created an hour ago will not appear in locate output until the next updatedb (tonight, on a default install). This is not a bug; it is how the index works. Use find for anything recent.
3. Expecting locate to filter by size or time. There is no locate -size or locate -mtime. The database stores path names, nothing else. Size, time, type, and permission filtering all require find.
4. Forgetting macOS does not build the locate DB. A locate query on a fresh Mac returns nothing useful. You must run sudo /usr/libexec/locate.updatedb once, or just use mdfind.
5. Assuming locate and plocate need different syntax. They do not. The query syntax is identical, so the muscle memory carries over when a distro upgrade swaps mlocate for plocate underneath you.
6. Using locate in a script. A script that depends on locate depends on a database that may be hours stale and may not exist at all on a minimal container image. Scripts should walk the filesystem with find so the result is real.
See also
- find Command Cheat Sheet: the full find reference covering name, type, size, permissions, and
-execpatterns - Find files containing text (find + grep): when you need to search file content, not file names
- Find files modified in the last 7 days: the
-mtimereference, a filterlocatecannot do - External: GNU findutils manual, plocate, fd on GitHub





