Vector database
A store that indexes embeddings for ANN search plus metadata filters, upserts, deletes and replication. Often Postgres + pgvector is enough.
A vector database stores embeddings and finds the ones nearest to a query quickly using an Approximate nearest neighbour (ANN) index. A real product also needs everything an ordinary database does: filtering by fields, updating and deleting records, backups, copies on several machines, and access control. That can be a dedicated system (Qdrant, Milvus, Pinecone, Weaviate) or an extension to a database you already run (pgvector for Postgres, vector fields in Elasticsearch/OpenSearch, Vespa).
A library catalogue that, instead of sorting books by title, shelves them by what they're about — and still lets you ask 'only books in French, published after 2020'.
Treating the vector database as the source of truth. Keep canonical text, metadata and ACLs in your primary store and treat the vector index as a rebuildable derivative; otherwise a corrupted index or a model change has no recovery path.
Under the hood: an ANN index (HNSW in almost all; IVF/PQ and on-disk graphs in Milvus, Zilliz, LanceDB, Turbopuffer-style object-storage designs), a payload store with secondary indexes for Metadata filtering (pre, post, filtered ANN), a write path (WAL → mutable segment → background index build, deletes as tombstones until Compaction & soft delete), and distribution (Sharding & partitioning, Replication). Choosing is mostly about what you already run and scale: pgvector keeps vectors transactional with your rows and ACLs — the right default to ~10M vectors per instance; Elasticsearch/OpenSearch if you already run them for BM25 (native hybrid); Qdrant/Milvus/Weaviate for 10M–1B with strong filtering and quantization; Vespa for large-scale hybrid ranking with custom rank expressions; managed serverless (Pinecone, Turbopuffer) when you'd rather pay per query than run nodes. The vendor matters less than: filtered recall on your data, update visibility latency, rebuild time, and backup/restore drills.
pgvector (0.8+) in the existing Postgres up to ~10M vectors: halfvec, HNSW m=16 / ef_construction=64–128, iterative scans for filters. Above that, or if Elasticsearch/OpenSearch already serves BM25, use its vector fields; for 50M+ with heavy filtering, Qdrant or Milvus with int8 quantization. Canonical data stays in the primary database.
Legal-contracts SaaS, 220 tenants, 4M clauses × 1024-d. Started on the existing Postgres 16 (RDS, 128 GB RAM) with pgvector halfvec HNSW: index 9 GB, p95 18 ms including tenant filter and ACL join, zero new infrastructure. At 35M clauses the HNSW index was 75 GB, builds took 6 hours and vacuum competed with OLTP. Moved vectors to Qdrant (3 nodes, int8, payload index on tenant) with Postgres as the source of truth via Change data capture (CDC); p95 7 ms.
Lead with 'do we need one?': "Under ~10M vectors and an existing Postgres, pgvector — transactional, ACL joins, one backup story. I move when index RAM, build time or vector QPS start hurting the OLTP workload." Expect: what do you lose by moving out? Transactions and joins; you now own sync (Dual-write or CDC) and Reconciliation job.
Numbers worth knowing
- pgvector comfortable range
- ≲10M vectors per instance768–1024-d halfvec HNSW, index fits in RAM alongside OLTP working set
- pgvector dims limits
- 2,000 (vector) / 4,000 (halfvec) indexedHNSW/IVFFlat index limits per pgvector README
- Update visibility
- ms (pgvector, transactional) to seconds (segment-based engines)depends on refresh/optimizer settings
How to decide
| When | Do this |
|---|---|
| < 10M vectors, Postgres already in use, ACLs in SQL | pgvector. |
| BM25 already in Elasticsearch/OpenSearch | Add vector fields there; native hybrid with RRF. |
| 50M+ vectors, heavy filters, quantization needed | Qdrant / Milvus / Vespa, Postgres stays source of truth via CDC. |
| Spiky, low average QPS and no ops team | Managed serverless; check per-query and storage pricing at your volume. |
Cost maths
pgvector on an existing DB: marginal cost ≈ RAM for the index. 5M × 1024-d halfvec ≈ 11 GB → maybe one instance size up (~$300–600/month extra, illustrative Oct 2026). Dedicated 3-node Qdrant at 64 GB each ≈ 3 × $310 = $930/month plus ops time. Rule of thumb: dedicated stores pay off when they let you shrink the primary DB or meet an SLA pgvector can't.
Operating it
- Leave pgvector when: HNSW index > 50% of instance RAM, index builds exceed the maintenance window, or vector queries push OLTP p99 up
- Filtered recall < 0.9 on small tenants despite iterative scans — move to an engine with filter-aware indexing
- Rebuild of the full index takes > 24 h — shard or move to segment-based incremental indexing
- Index size / RAM per node — alert above 70%
- Write-to-searchable lag — alert above 60 s (or your freshness SLO)
- Source-of-truth vs index count drift (Reconciliation job) — alert above 0.1%
When it goes wrong
Checkout latency on an e-commerce site spiked every night at 02:00.
OLTP p99 dashboard; pg_stat_activity showed a REINDEX on the product-embedding HNSW index holding CPU and I/O.
A nightly job rebuilt the 40 GB pgvector index on the primary to absorb catalog churn; it competed with order writes.
Moved vector search to a read replica (later to a dedicated Qdrant cluster fed by CDC), replaced nightly rebuilds with incremental upserts, and set a 'vector workload must not touch primary' rule.
Related terms
Where it shows up
Sources
- pgvector: open-source vector similarity search for Postgres — pgvector project, 2026docs
- Survey of Vector Database Management Systems — Pan, Wang & Li, 2023paper
- Qdrant documentation: Indexing — Qdrant, 2026docs
- Elasticsearch reference: k-nearest neighbor (kNN) search — Elastic, 2026docs
Check yourself
Three questions. Every option is explained once you answer.