pip install whoosh3 away on any machine that has Python.
grep and ripgrep are brilliant at what they do:
find every line that matches a pattern, fast. But sometimes that isn't the
question you're asking. When you type a couple of words into a notes folder
or a docs tree, you usually don't want every line that mentions
them — you want the few files that are most about them, best first.
That's a ranking problem, and it's exactly what a full-text index is for.
The whoosh CLI gives you that with three commands:
whoosh index to build the index, whoosh search
to query it, and whoosh stats to inspect it. Here's the whole
thing, start to finish.
Install
pip install whoosh3
That's it — no build step. It installs a whoosh console script.
(The distribution is named whoosh3 on PyPI; the import name and
the command are both whoosh.)
Index a folder
Point it at a directory. It walks the tree, reads common text and source
files, and stores a compact index in a .whoosh_index/ folder:
$ whoosh index .
Indexed /home/you/notes
3 added -> 3 docs total in 0.03s
index stored at /home/you/notes/.whoosh_index
By default it picks up common text and source extensions. Narrow or widen
that with --ext:
$ whoosh index docs --ext md,rst,txt
Re-run any time. Pass --update for an incremental refresh — it
only re-reads files that changed and drops ones you deleted, which is much
faster on a big tree:
$ whoosh index . --update
Skip generated or vendored files with --exclude (a glob, and
you can repeat it), and preview exactly what would be indexed —
without creating or touching an index — with --dry-run:
$ whoosh index . --exclude 'build/*' --dry-run
Would index 4 files under /home/you/proj
README.txt
docs/install.md
docs/quickstart.md
src/index.py
--dry-run is the safe way to tune your --ext and
--exclude filters before committing to a build — it never
writes, clears, or creates .whoosh_index/.
Search it
Now query. Results come back ranked, with the matched terms highlighted and a relevance score:
$ whoosh search "search"
3 matches for 'search':
1. README.txt (score 1.50)
Project SEARCH tools. Fast, pure-Python full-text SEARCH with Whoosh
2. src/index.py (score 0.92)
every text file under path for full-text SEARCH
3. docs/quickstart.md (score 0.85)
add documents to an index, then run a SEARCH query. Whoosh is pure Python, so there is no
Notice the file that's genuinely about search sorts above the ones that merely mention it in passing. That ordering is the whole point — it's what a raw substring search can't give you.
The query language
The query is more than a bag of words. You get boolean operators, quoted phrases, and field-scoped terms, straight from the shell:
# boolean
$ whoosh search "pip OR schema"
# exact phrase
$ whoosh search '"pure Python"'
# exclude a term
$ whoosh search "search NOT python"
# scope to a field inline (title = file name, body = file contents)
$ whoosh search "body:install"
You can also scope with the --field flag, which is repeatable
and reads more clearly for a whole query. By default a search covers both
title and body; pin it to one:
$ whoosh search "index" --field body
Order by recency, and size the snippets
Relevance is the default sort, but sometimes "what did I touch most
recently?" is the real question. --sort-by mtime orders hits
by file modification time, newest first — handy for notes and work logs:
$ whoosh search "search OR python" --sort-by mtime --no-highlight --snippet-chars 50
4 matches for 'search OR python':
1. README.txt (score 3.00)
Project search tools. Fast, pure-Python full-text...
2. src/index.py (score 2.00)
# Build a Whoosh index from a folder of documents....
3. docs/quickstart.md (score 1.00)
# Quickstart Create a schema, add documents to an...
4. docs/install.md (score 0.00)
# Installation Install with pip: `pip install whoo...
Here the newest file (README.txt) comes first regardless of how
strongly it matches — the order is by modification time, not relevance. Two
more knobs there: --snippet-chars N controls how much context
each result shows (default 200), and --no-highlight prints a
plain, grep-friendly leading slice of the body with no match markup — nice
when you're piping into another tool.
Output for humans and for scripts
The default output is made for reading. When you're piping into something else, switch formats:
| Flag | What you get |
|---|---|
--json | Machine-readable results — pipe straight into jq. |
--count | Just the number of matching documents. |
--html | <mark>…</mark> highlights instead of UPPERCASE. |
--no-highlight | Plain leading slice of the body, no match markup — grep-friendly. |
--fields | Choose which stored fields appear in the output. |
--field | Restrict the search to a field (repeatable; default title + body). |
--snippet-chars | How much context to show per result (default 200). |
--sort-by | score (default) or mtime for newest-first. |
--limit | Cap the number of results (default 10). |
$ whoosh search "bm25 OR grep" --count
2
$ whoosh search "install" --json --fields path
[{"path": "docs/install.md"}]
Because --json is stable and quiet, you can build small tools on
top of it — a "search my notes" alias, a pre-commit doc check, a fuzzy file
opener — without ever leaving the shell.
Inspect the index with whoosh stats
Once you've built an index, whoosh stats tells you what's in it
— how many documents, which fields, and how much disk it uses:
$ whoosh stats
Index: /home/you/proj/.whoosh_index
documents: 4
fields: 4
- body (TEXT)
- mtime (NUMERIC)
- path (ID)
- title (TEXT)
size on disk: 17.4 KB (3 files)
last updated: 2026-07-18 03:04:32
Add --top-terms FIELD to see the most frequent indexed terms —
a quick way to understand what a corpus is actually about (and a reminder
that body is stemmed, so install and
installation collapse to one term, instal):
$ whoosh stats --top-terms body --top 6
Top terms in 'body':
4 search
4 instal
3 whoosh
3 text
3 python
3 index
Both commands also take --json, so index health checks drop
straight into a script or a CI step.
When to reach for this (and when not to)
- Reach for it when you want the most relevant files, not every matching line: searching a notes vault, a docs tree, a corpus of transcripts or logs you keep coming back to.
- Reach for it when you'll query the same folder repeatedly — building the index once and searching it many times is where ranking pays off.
- Stick with
grep/ripgrepfor one-shot pattern hunts across code, regex matching, or when you truly need every occurrence. They're not competitors so much as different tools; I reach for both, on different days.
Install from PyPI · Python quickstart · Try the live demo
See also: Whoosh vs SQLite FTS5 · Whoosh vs Tantivy · Whoosh vs Elasticsearch