Two Extensions. Complete Search.

Postgres

pg_textsearch

BM25 / Keyword

pgvectorscale

Vector / Semantic

Zero Complexity

Forget provisioning three separate systems. It's just one database.

Zero Latency

Queries run where your data lives. No ETL pipelines or sync lag.

Total Consistency

Single source of truth. Writes and searches are transactionally safe.

pg_textsearch

BM25 / Keyword

Modern ranked text search as a native Postgres extension. Industry-standard BM25 scoring with the <@> operator, Block-Max WAND optimization, and parallel index builds.

CREATE INDEX ON documents USING bm25(content) WITH (text_config='english'); SELECT * FROM documents ORDER BY content <@> 'database system' LIMIT 10;

Supports 29 languages

Configurable parameters

View on GitHub

pgvectorscale

Vector / Semantic

High-performance embedding search built on top of pgvector. The StreamingDiskANN index delivers 28x lower p95 latency and 16x higher throughput than Pinecone's storage-optimized index.

CREATE INDEX ON documents USING diskann (embedding vector_cosine_ops); SELECT * FROM documents ORDER BY embedding <=> $query_vector LIMIT 10;

75% less cost on AWS

Statistical Binary Quantization

View on GitHub

The Killer Feature

Hybrid Search in a Single Query

The real power is using both together. Combine the lexical precision of BM25 with the semantic understanding of vector embeddings—without leaving your database, without an external reranker, and without syncing data.

-- BM25 keyword results WITH keyword_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY content <@> 'search query') AS rank_kw FROM documents ORDER BY content <@> 'search query' LIMIT 20 ), -- Vector similarity results semantic_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY embedding <=> $query_vec) AS rank_vec FROM documents ORDER BY embedding <=> $query_vec LIMIT 20 ) -- Reciprocal Rank Fusion SELECT COALESCE(k.id, s.id) AS id, COALESCE(1.0/(60 + k.rank_kw), 0) + COALESCE(1.0/(60 + s.rank_vec), 0) AS rrf_score FROM keyword_results k FULL OUTER JOIN semantic_results s ON k.id = s.id ORDER BY rrf_score DESC LIMIT 10;

How RRF works

Run BM25 keyword search and vector similarity search in parallel, then fuse results using Reciprocal Rank Fusion. One database, one query layer, state-of-the-art retrieval quality.

Why Build Search on Postgres?

Why build search on postgres?

One system to operate

No ETL pipelines. No sync jobs. No eventual consistency. Insert a row and it's searchable.

ACID guarantees for search

Your search index participates in transactions. Rollback a write and the index rolls back with it.

Security you already have

Row-level security, roles, and permissions apply to search queries automatically.

Backups include everything

pg_dump, streaming replication, point-in-time recovery—your search indexes are just part of your database.

SQL you already know

No new query language. No client library. ORDER BY, LIMIT, WHERE, JOIN—search composes with everything else.

Up and Running in Five Minutes

Get started with standard Postgres tools.

# Install pg_textsearch cd /tmp && git clone https://github.com/timescale/pg_textsearch cd pg_textsearch && make && make install # Install pgvectorscale (requires Rust) cd /tmp && git clone https://github.com/timescale/pgvectorscale cd pgvectorscale/pgvectorscale cargo pgrx install --release
-- Enable both extensions CREATE EXTENSION pg_textsearch; CREATE EXTENSION vectorscale CASCADE; -- also installs pgvector -- You now have BM25 + vector search in one database