We ran both in parallel for 90 days across three million documents. Here are the exact numbers, the trade-offs, and why we ended up keeping the answer that surprised us.
The assumption going in was simple: Elasticsearch is the search tool, Postgres is the database. After ninety days running both in parallel, we kept Postgres.
For our workload — three million documents, mostly English-language, with prefix matching and ranked results — Postgres tsvector kept up with Elasticsearch on every metric that mattered. Query latency was within 30ms at p99. Index rebuild time was faster. Operational overhead was dramatically lower.
Elasticsearch won on relevance tuning. If your product lives or dies on subtle ranking, the BM25 control you get in Elasticsearch is worth the complexity. For us, it was not worth one more service to monitor, one more cluster to scale, one more outage vector.
The inflection point is roughly ten million documents with heavy faceting. Below that, Postgres full-text search with a GIN index is a serious competitor that most teams underestimate.