fsearch README

The project's README from github.com/noahdunnagan/fsearch. As one markdown file: README.md.

FSearch

Whole-disk file search for macOS: names in about 0.1 ms, typo-tolerant, plus indexed search inside files. A CLI with a small daemon, or a Rust crate.

cargo build --release && ./target/release/fsearch install   # -> ~/.local/bin/fsearch
fsearch fsearch main              # find files by name
fsearch 'ext:rs grep:apply_dir'   # search inside files

Speed

M4 Max, 8.3M files on disk, vs the previous version (76d612f). Same results. Medians.

before now
find a file by name 1.0 ms 0.13 ms 7.7×
typing a whole filename, all keystrokes 23 ms 3.0 ms 7.5×
search inside files 14 ms 2.3 ms 6.2×
slowest 10% inside files (Chromium) 38 ms 2.3 ms 16×
CLI, launch to answer 5.5 ms 3.3 ms 1.7×
first run, fully searchable 101 s 49 s 2.1×
first run, peak memory 1.2 GB 0.9 GB
index on disk (Chromium) 0.32 GB 0.76 GB 2.4× bigger

The index grew because each file carries a filter that lets search skip files without the text.

Queries

fsearch 'readme in:~/Developer'          # inside a folder
fsearch 'type:image size:>5mb mtime:<7d'
fsearch 'ext:rs regex:fn\s+\w+_dir'      # regex inside files
fsearch 'sym:apply_dir'                  # where it's defined

Words are fuzzy, and 5+ letter words forgive one typo (mian.rs finds main.rs). Also 'exact, ^prefix, suffix$ and !exclude. Filters: ext: type: kind: in: size: mtime: re: path: grep: regex: sym: limit:. Content search is smart-case.

Full Disk Access

From a terminal with Full Disk Access it indexes everything. As a login item (fsearch install --login), grant ~/.local/bin/fsearch access in System Settings > Privacy & Security, again after each rebuild. Without access it skips protected folders instead of prompting.

API

JSON lines over ~/Library/Application Support/FSearch/fsearch.sock, or fsearch stdio:

{"q": "fsearch main", "limit": 20}
{"op": "grep", "pattern": "apply_dir", "in": "~/Developer"}

Or link the crate:

let engine = fsearch::Engine::start(fsearch::Options { dir: fsearch::default_dir(&home), home: home.clone(), skip: None })?;
let hits = engine.search(&fsearch::Query::parse("fsearch main", &home)?)?;

An app and the CLI share one index: the first process owns it, the rest follow.

How it works

fsearch (noahdunnagan/fsearch)

high-performance
Searching Database…

2.1K ·GitHub
What is this?FSearch is a whole-disk file search tool for macOS that finds any file by name in about a millisecond, tolerates typos, and can search inside file contents using an index.
Is this a CLI tool or a Rust library?Both: it ships as a CLI backed by a small background daemon, and the same functionality can be linked into your own project as a Rust crate.
How do I get it running?Run it from a terminal with Full Disk Access granted so it can crawl the whole disk, and optionally register it as a login item with fsearch install --login so it starts automatically.
Do I need to grant Full Disk Access first?For full coverage yes - FSearch needs Full Disk Access in System Settings, and that grant has to be redone after each rebuild of the binary.
What happens if I don't grant Full Disk Access?It won't nag you with a permission prompt - it just silently skips the protected folders it can't see while still indexing everything else.
Does it run on Linux too, or is it macOS-only?It's built specifically for macOS: it relies on getattrlistbulk and FSEvents for crawling and live updates, and permissions go through macOS System Settings.
Does my data leave the machine?No - everything runs locally: a background daemon crawls the disk once and keeps an index on-device, with content matches read fresh from local disk rather than stored or sent anywhere.
How does fsearch compare to a tool like fff?On a 509k-file test, fsearch finds files by name in 1.1ms vs 13.8ms for fff, searches contents in 5.6ms vs 53ms, and uses 50MB of memory for the whole disk vs 358MB for fff on just one folder.
What query syntax does it support?Queries are fuzzy by default (words of 5+ letters forgive one typo), and you can use 'exact, ^prefix, suffix$ and !exclude, plus filters like ext:, type:, kind:, in:, size:, mtime:, re:, path:, grep:, regex:, sym: and limit:.
How does it stay up to date as files change?It crawls the whole disk once at startup with getattrlistbulk, then keeps itself current by watching FSEvents, so new, renamed, or deleted files show up in about 0.1 seconds; a restart only replays what changed since.
Can an app and the CLI share the same search index?Yes - FSearch exposes JSON lines over a Unix socket at ~/Library/Application Support/FSearch/fsearch.sock (or via stdio), and the first process to start owns the index while any others just follow along.
What are similar projects?ripgrep, memex, meilisearch, fff, leviathan, sonic, tantivy, typesense
Size
3.2 MB
Stars
2.1K
Age
9d
Commits · 90 Days