Experiment · 2026
Search Without Elasticsearch
- Postgres
- Search
How far Postgres full-text search actually goes before you need a dedicated engine. Further than I expected.
01 — WhyWhat made this worth building
Every project I join has a ticket to "add Elasticsearch for search". Usually the dataset is under a million rows and Postgres would answer in under 20ms with a GIN index. I wanted a defensible number for where that stops being true.
02 — NotesHow it works
A `tsvector` column with a GIN index gets you stemming, ranking, prefix matching and boolean operators. Combine it with `pg_trgm` for fuzzy matching and you have covered typo tolerance too — which is the feature people usually think they need a search engine for.
alter table article
add column search tsvector
generated always as (
setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(body, '')), 'B')
) stored;
create index on article using gin (search);
select title, ts_rank(search, query) as rank
from article, websearch_to_tsquery('english', $1) query
where search @@ query
order by rank desc
limit 20;Still open: where this actually falls over. So far the honest answer is that relevance tuning gets awkward before performance does. Faceting across many dimensions and true typo-tolerant ranking are where a dedicated engine earns its operational cost.