<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz" -->

---
title: Postgres Full-Text Search Instead of Elasticsearch
description: Postgres has built-in full-text search via tsvector, GIN indexes, websearch_to_tsquery, and ts_rank — covering stemming, relevance ranking, phrase queries, and...
canonical: https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Postgres Full-Text Search Instead of Elasticsearch | daily.dev
og:description: Postgres has built-in full-text search via tsvector, GIN indexes, websearch_to_tsquery, and ts_rank — covering stemming, relevance ranking, phrase queries, and...
og:url: https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz
og:image: https://api.daily.dev/og/posts/85sLAiBvZ.png
og:image:alt: Postgres Full-Text Search Instead of Elasticsearch
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Postgres Full-Text Search Instead of Elasticsearch

**[Prisma Blog](https://daily.dev/sources/prisma-blog)** · 12 min read · 0 upvotes · 0 comments

## Summary

Postgres has built-in full-text search via tsvector, GIN indexes, websearch_to_tsquery, and ts_rank — covering stemming, relevance ranking, phrase queries, and highlighted snippets without any external search engine. A generated tsvector column with weighted fields (title vs body) plus a GIN index is all that's needed for ranked search. Typo tolerance is handled by the pg_trgm extension using trigram similarity, enabling 'did you mean' suggestions from within the same database. The post walks through a complete TypeScript/Bun demo against Prisma Postgres, showing ranking, stemming, websearch syntax, and trigram fallback in action. Elasticsearch still wins for corpus-wide BM25 relevance tuning, faceted analytics at scale, log/event search, and multi-language pipelines — but for most apps, Postgres already handles the job.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.prisma.io/blog/you-dont-need-elasticsearch-postgres-already-has-full-text-search>

## Questions this post answers

### How do I build typo-tolerant full-text search in Postgres without Elasticsearch?

Combine a generated tsvector column with a GIN index for full-text search, then add the pg_trgm extension for typo tolerance. Use websearch_to_tsquery to parse user input, ts_rank to order results by relevance, and a trigram similarity match (the % operator with a gin_trgm_ops index) as a fallback when a full-text search returns zero results.

_Developers weighing Postgres search against a dedicated engine can dig deeper into tradeoffs on daily.dev._

### What is the difference between Postgres ts_rank and Elasticsearch BM25 for search relevance?

ts_rank scores each document against a query in isolation, without considering how rare a term is across the whole corpus, while Elasticsearch uses BM25 scoring that factors in corpus-wide term statistics. On a focused corpus like a single app's own documents or products this difference rarely matters, but on large, heterogeneous text collections BM25's per-field boosting and rarity weighting start to produce noticeably better rankings.

_Teams deciding between Postgres and Elasticsearch for relevance-critical search can compare approaches on daily.dev._

### Why does my Postgres full-text search return nothing for a misspelled query even though the correct word exists?

Postgres full-text search normalizes correct words through stemming but does nothing for misspellings, since a typo like 'conection' is not a stem of 'connection' and tsquery simply finds no match. The fix is the pg_trgm extension, which compares strings by overlapping three-character trigrams and returns similarity scores above a threshold, letting a failed full-text search fall back to a trigram-based 'did you mean' suggestion.

_Developers debugging empty search results can find fixes like this trigram fallback via daily.dev._

## Similar posts on daily.dev

- [Watch Out Elasticsearch\! Tiger Data's PostgreSQL BM25 Search Extension Goes Open Source](https://daily.dev/posts/watch-out-elasticsearch-tiger-data-s-postgresql-bm25-search-extension-goes-open-source-i9m2ohtmp) · It's Foss · 32 upvotes · 0 comments
- [GitHub - timescale/pg\_textsearch: PostgreSQL extension for BM25 relevance-ranked full-text search. Postgres OSS licensed.](https://daily.dev/posts/github---timescale-pg-textsearch-postgresql-extension-for-bm25-relevance-ranked-full-text-search-p-xeiapecnq) · Hacker News · 11 upvotes · 0 comments
- [Speeding Up PostgreSQL Full-Text Search with Persistent TSVectors](https://daily.dev/posts/speeding-up-postgresql-full-text-search-with-persistent-tsvectors-bqhvmf0uf) · RUBYLAND · 0 upvotes · 0 comments

---

Tags: [#postgresql](https://daily.dev/tags/postgresql), [#elk](https://daily.dev/tags/elk), [#prisma](https://daily.dev/tags/prisma), [#full-text-search](https://daily.dev/tags/full-text-search)

[View this post on daily.dev](https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Postgres Full-Text Search Instead of Elasticsearch","url":"https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz"},"datePublished":"2026-07-22T11:07:47.164Z","dateModified":"2026-09-13T19:16:29.560Z","description":"Postgres has built-in full-text search via tsvector, GIN indexes, websearch_to_tsquery, and ts_rank — covering stemming, relevance ranking, phrase queries, and...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/5610660ca2119eb340e1460c1b08f786?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/5610660ca2119eb340e1460c1b08f786?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Prisma Blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Prisma Blog","logo":"https://media.daily.dev/image/upload/s--wjA5CgSL--/f_auto,q_auto/v1780213432/logos/prisma-blog?_a=BAMAMiWQ0","url":"https://daily.dev/sources/prisma-blog"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"postgresql,elk,prisma,full-text-search","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Prisma Blog","item":"https://daily.dev/sources/prisma-blog"},{"@type":"ListItem","position":3,"name":"Postgres Full-Text Search Instead of Elasticsearch"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/postgres-full-text-search-instead-of-elasticsearch-85slaibvz#faq","mainEntity":[{"@type":"Question","name":"How do I build typo-tolerant full-text search in Postgres without Elasticsearch?","acceptedAnswer":{"@type":"Answer","text":"Combine a generated tsvector column with a GIN index for full-text search, then add the pg_trgm extension for typo tolerance. Use websearch_to_tsquery to parse user input, ts_rank to order results by relevance, and a trigram similarity match (the % operator with a gin_trgm_ops index) as a fallback when a full-text search returns zero results. Developers weighing Postgres search against a dedicated engine can dig deeper into tradeoffs on daily.dev."}},{"@type":"Question","name":"What is the difference between Postgres ts_rank and Elasticsearch BM25 for search relevance?","acceptedAnswer":{"@type":"Answer","text":"ts_rank scores each document against a query in isolation, without considering how rare a term is across the whole corpus, while Elasticsearch uses BM25 scoring that factors in corpus-wide term statistics. On a focused corpus like a single app's own documents or products this difference rarely matters, but on large, heterogeneous text collections BM25's per-field boosting and rarity weighting start to produce noticeably better rankings. Teams deciding between Postgres and Elasticsearch for relevance-critical search can compare approaches on daily.dev."}},{"@type":"Question","name":"Why does my Postgres full-text search return nothing for a misspelled query even though the correct word exists?","acceptedAnswer":{"@type":"Answer","text":"Postgres full-text search normalizes correct words through stemming but does nothing for misspellings, since a typo like 'conection' is not a stem of 'connection' and tsquery simply finds no match. The fix is the pg_trgm extension, which compares strings by overlapping three-character trigrams and returns similarity scores above a threshold, letting a failed full-text search fall back to a trigram-based 'did you mean' suggestion. Developers debugging empty search results can find fixes like this trigram fallback via daily.dev."}}]}
```

