David John Thammineni
AI Engineering25 May 20233 min read

Choosing a Vector Database: pgvector Until It Hurts

Choosing a Vector Database: pgvector Until It Hurts

Every RAG tutorial jumps straight to a dedicated vector database, and every architecture review I do this year asks "which one?" My answer, boringly often: Postgres.

pgvector until it hurts

If your embeddings live where your application data already lives, an entire class of sync problems disappears:

CREATE EXTENSION vector;

CREATE TABLE chunks (
  id bigserial PRIMARY KEY,
  document_id bigint REFERENCES documents(id),
  content text,
  embedding vector(1536)
);

-- top-5 nearest by cosine distance, filtered by tenant
SELECT content, 1 - (embedding <=> $1) AS score
FROM chunks
WHERE document_id IN (SELECT id FROM documents WHERE org_id = $2)
ORDER BY embedding <=> $1
LIMIT 5;

Notice the WHERE clause: filtering by tenant/permissions in the same query as similarity. In a separate vector DB, that's metadata-filter APIs, dual writes, and eventual-consistency bugs between your source of truth and your index. Below a few million vectors, pgvector with an IVFFlat index handles it with latency indistinguishable from the dedicated players.

When it starts to hurt

Real reasons to graduate: tens of millions of vectors, heavy write throughput with immediate searchability needs, or recall requirements that demand tuned HNSW at scale. Then the shortlist:

  • Pinecone — managed, boring, expensive; the "we don't want to operate this" pick.
  • Weaviate/Qdrant — self-hostable, strong filtering, hybrid search built in.
  • Chroma — great for local dev and prototypes; embed it like SQLite.

The two features that actually matter

Benchmarks obsess over queries-per-second; production cares about different things. Metadata filtering: nearly every real query is "similar to X, where user has access and doc is current" — evaluate how each store handles filtered search, because naive post-filtering silently ruins recall. Hybrid search: pure vectors miss exact identifiers (SKUs, error codes, names); combining BM25 keyword scores with vector similarity fixes the demo-day embarrassment of searching an invoice number and getting philosophy back.

Start with pgvector, instrument recall on your actual queries, and migrate when data — not fashion — tells you to.

Keep Reading