pip install
whoosh3 and nothing else to deploy. If you need to search across many
machines, ingest a firehose of logs, serve very high query volumes, or want
the analytics/aggregation ecosystem around it, run
Elasticsearch (or OpenSearch). The real question isn't
"which is faster" — it's "do I need a distributed server at all?"
Elasticsearch is a fantastic piece of engineering, and for a huge class of problems it's the right answer. But a lot of teams reach for it out of habit and end up running a JVM cluster to power a search box over a few tens of thousands of rows. This page is an honest guide to when an embedded library like Whoosh does the job with a fraction of the operational cost — and when it genuinely doesn't and you should reach for the server.
The one-line difference
- Whoosh is a full-text search library written entirely in Python. It runs inside your process and writes its index to a directory on disk. There is no server, no port, no cluster — just an import.
- Elasticsearch is a distributed search server built on Apache Lucene. You run it as a separate JVM service (often a cluster), and your app talks to it over HTTP. It's designed for scale, replication, and multi-node operation.
At a glance
Whoosh (whoosh3) | Elasticsearch | |
|---|---|---|
| What it is | Embedded library, in-process | Standalone distributed server (JVM), talked to over HTTP |
| Install / deploy | pip install whoosh3; index is a local folder | Run and operate a service/cluster (or pay for a managed one); a client library in your app |
| Runtime deps | None — pure Python | A running Elasticsearch node/cluster + the JVM |
| Operational overhead | None beyond your app | Provisioning, heap tuning, shards/replicas, upgrades, monitoring, backups |
| Scale ceiling | One machine; comfortable into the low millions of docs | Horizontal — scales across many nodes to very large corpora |
| Ranking | BM25F (default), TF-IDF, pluggable in Python | BM25 (Lucene), highly configurable |
| Query features | Boolean, phrase, range, wildcard, fuzzy, fields, faceting, highlighting, spelling | Very rich: full query DSL, aggregations, geo, percolation, vectors, and more |
| Analytics / aggregations | Faceting and grouping | Deep aggregation framework; a whole analytics ecosystem (Kibana, etc.) |
| Near-real-time distributed indexing | Single-writer, local | Yes — built for it |
| High availability / replication | Not built in (it's a library) | Built in — shards and replicas across nodes |
| Best fit | Embedded search in one app/box; you value zero ops and pure Python | Large scale, high query volume, multi-node, or log/analytics workloads |
Where Whoosh wins
- No server to run. This is the big one. There's no cluster to provision, no heap to tune, no shard strategy, no version upgrades to coordinate, and no extra thing that can be down at 3am. Your search index is a folder next to your app.
- Trivial deploy and dev setup. A pure-Python wheel with
zero runtime dependencies drops into any environment — a laptop, a single
container, a serverless function, locked-down CI — with no external service.
New contributors
pip installand they're running. - You program it in Python. Custom scoring, a bespoke analyzer, or a new storage backend are all plain Python you can read and step through. No cluster config language, no plugins to compile.
- It runs where servers can't. PyPy and even the browser via WebAssembly (Pyodide) are supported — the live demo on this site is the entire search engine running client-side, no backend at all.
- Lower cost, less surface area. No always-on JVM node to pay for and secure. Fewer moving parts is fewer things that break.
Where Elasticsearch wins
- Scale past one machine. Sharding and replication across nodes let you index and query far more data than any single-process library.
- High availability. Replicas mean a node can fail and search keeps serving — something a local library simply doesn't offer.
- Throughput. Many queries per second and large ingest rates (logs, events, metrics) are what it's built for.
- Analytics & ecosystem. Aggregations, dashboards (Kibana), vector search, geo, and a large surrounding toolset go well beyond "find documents matching a query."
- Language-agnostic service. Any app in any language can hit the same HTTP API — useful in a polyglot architecture.
The same search, without a server
Here's full-text search over a couple of documents in Whoosh — indexing, querying, and ranked results, with nothing running but Python:
from whoosh.fields import Schema, TEXT, ID
from whoosh.index import create_in
from whoosh.qparser import QueryParser
import os, tempfile
d = tempfile.mkdtemp()
schema = Schema(title=TEXT(stored=True), body=TEXT)
ix = create_in(d, schema) # index is just this folder
w = ix.writer()
w.add_document(title="First", body="the quick brown fox")
w.add_document(title="Second", body="a lazy brown dog")
w.commit()
with ix.searcher() as s:
q = QueryParser("body", ix.schema).parse("brown")
for hit in s.search(q):
print(hit["title"])
The Elasticsearch equivalent needs a running node first, then something like this via the official client — note that the index lives in the server, not your process:
from elasticsearch import Elasticsearch
es = Elasticsearch("http://localhost:9200") # a server must be running
es.index(index="docs", id=1, document={"title": "First", "body": "the quick brown fox"})
es.index(index="docs", id=2, document={"title": "Second", "body": "a lazy brown dog"})
es.indices.refresh(index="docs")
res = es.search(index="docs", query={"match": {"body": "brown"}})
for hit in res["hits"]["hits"]:
print(hit["_source"]["title"])
Both return the same two documents ranked by relevance. The difference is everything around the code: one needs infrastructure, the other doesn't.
A useful middle path
You don't have to choose forever on day one. A common, low-regret pattern
is to start with Whoosh while your data lives on one machine,
keep your search behind a small interface in your app (an index()
and a search() function), and only migrate to Elasticsearch if and
when you actually outgrow a single box. Most projects never do — and the ones
that do will have real traffic data to size the cluster properly instead of
guessing up front.
How to choose
Pick Elasticsearch (or OpenSearch) if:
- Your corpus won't fit comfortably on one machine, or you expect it to grow that way.
- You need high availability, replication, or very high query throughput.
- You're doing log/metrics analytics or need heavy aggregations and dashboards.
- Multiple services in different languages need to share one search backend.
- You already run it and the operational cost is paid for.
Pick Whoosh if:
- Your data fits on one machine — thousands to low millions of documents.
- You don't want to run, secure, and upgrade a separate search service.
- You want a dependency-free
pip installthat works in minimal containers, serverless, and locked-down CI. - You want to customise scoring, analysis, or storage in plain Python.
- You need PyPy or in-browser (WebAssembly) support.
Whoosh is maintained again. It's pure Python, zero runtime dependencies, BSD-2-Clause, with a live browser demo and modern packaging.
⭐ Star Whoosh on GitHub · Try the live demo · pip install whoosh3
See also: Whoosh vs SQLite FTS5 · Whoosh vs Tantivy · Search files from the command line.