Home/ Blog/ Article

Postgres full-text search or Elasticsearch: choosing a search engine for your product

·

Most products with a list of anything in them eventually need a search box. The question that follows is rarely asked early enough: does this search box need Elasticsearch, or does the database already running the product do the job? Get it wrong in one direction and users get poor results from something that looks like search but isn’t. Get it wrong in the other direction and the team spends weeks standing up and operating a cluster nobody has the spare capacity to keep healthy.

This is a different question from choosing a vector database for an AI feature. Semantic search finds results by meaning, using embeddings and similarity queries, and is worth its own decision entirely. What we’re covering here is the far more common case: a user types a word or phrase and expects to find the records that contain it, ranked in a sensible order. Most products need this working well before they need anything AI-shaped.

What the database you already run can do

PostgreSQL has had proper full-text search built in for a long time, and it’s more capable than most teams give it credit for. A tsvector column stores a normalised, stemmed representation of the text; a GIN index makes searching it fast; ts_rank gives you relevance ordering rather than an arbitrary sort; and the pg_trgm extension adds trigram matching for typo tolerance and partial-match queries that a plain LIKE can’t do efficiently. None of this requires new infrastructure. It runs in the same database that already holds the data, gets backed up the same way, and shows up in the same monitoring.

For a support ticket list, a product catalogue, an internal admin search, or most SaaS features where search is useful but not the product itself, this is usually enough. It stays enough for longer than most people expect, well past the point where a dataset feels large from the inside.

Where it starts to strain

The limits aren’t really about row count on their own. They show up as specific, nameable requirements:

  • Faceted search. Filtering and counting results across several independent dimensions at once (category, price band, location, status) gets expensive to express well in SQL as the number of facets grows.
  • Relevance tuning as a product requirement. If a product owner wants to boost certain fields, apply synonyms, or tune ranking based on user behaviour, Postgres can do some of this, but it becomes bespoke SQL rather than configuration.
  • Multi-language content in one index. Postgres text search configurations are per-language; running several well across a single searchable set of documents takes real setup.
  • Search-as-you-type at scale. Instant, incremental results across a large corpus is where a purpose-built inverted index starts to visibly outperform a general-purpose database doing a secondary job.
  • Isolating search load from transactional load. A heavy search feature competing for the same CPU and I/O as your order processing or booking flow is a capacity problem worth solving separately once it’s real.

The pattern worth noticing: these are requirements you can point to, not a vague sense that search should feel better. If nobody can name which of these applies, that’s information too.

What a dedicated search engine adds, and what it costs

Elasticsearch and OpenSearch are built around inverted indices designed specifically for text: language analysers per field, tunable relevance scoring, aggregations that would be painful to write in SQL, and horizontal scaling independent of your primary datastore. When search genuinely is the product, or close to it, this capability is worth having.

It comes with a second system to run. That means patching, monitoring, capacity planning, and access control for a stateful cluster, on top of whatever you already operate. It also means keeping the search index in sync with the source of truth, usually through change data capture or dual writes, which introduces a new class of bug: the record is correct in the database and stale or missing in the index, and nobody notices until a customer reports it. None of this is a reason to avoid Elasticsearch. It’s a reason to make sure the team taking it on has, or is budgeting for, the operational capacity to run it properly, whether that’s in-house or through a managed offering such as Elastic Cloud or Amazon OpenSearch Service.

The middle ground worth knowing about

Between extending Postgres and running Elasticsearch sits a set of purpose-built search services and lighter engines: Algolia and Typesense as examples, and Meilisearch as a self-hosted option. These generally give better out-of-the-box relevance and instant-search behaviour than rolling your own on Postgres, with much less operational weight than a self-managed Elasticsearch cluster. The trade-off moves rather than disappears: a hosted service means an external dependency and a cost that scales with records or queries, and even the self-hosted options still need to be kept in sync with your primary data. They’re worth evaluating specifically when the requirement is good search, shipped quickly, without hiring for search infrastructure.

Questions to answer before choosing

A few honest answers up front save a lot of rework later:

  • How many searchable records will there actually be in a year, not at launch, and is that number based on a real forecast or a guess?
  • Is search a supporting feature, or is it close to the main way users interact with the product?
  • Has anyone specified a concrete relevance or faceting requirement, or is better search the whole brief so far?
  • Does the team have the capacity to run and monitor another stateful system, or would that fall on whoever is already stretched thinnest?
  • If the search index and the source of truth briefly disagree, is that acceptable for this product, or does it need to be immediately consistent?

A decision worth revisiting

Start with what the database already gives you, because it’s free, it’s already operated, and it covers more cases than reputation suggests. Move to a dedicated engine when you can name the specific limit you’ve hit: faceting, relevance tuning as a product feature, multi-language analysis at scale, or load isolation, rather than because a search box in a mockup made the idea appealing. Treat the choice as reversible: a search layer that reads from the same source of truth can usually be swapped later without touching the rest of the system, provided the boundary between how the product searches and how it stores data was kept reasonably clean from the start.

Filed under: