Long, bright library aisle lined with bookshelves

How to choose a vector database in 2026 (and whether you need one)

Most teams don't need a new database — they need better retrieval. Here is how we decide between extending what you run, a dedicated engine, or object-storage-first, with the costs worked out.

By ForthClover EngineeringUpdated October 202613 min readInfrastructure

The most common question we get on RAG engagements is which vector database should we use? The honest answer has changed since the first wave of RAG projects. Postgres and the search engines teams already run now do vector search well, object storage has become a credible place to keep vectors, and every hyperscaler sells a managed retrieval layer. The database matters less than it did. Retrieval quality — hybrid search, reranking, filtering, evaluation — matters more.

We have shipped production retrieval on pgvector, OpenSearch, Pinecone, Qdrant and Weaviate, and evaluated most of the newer options. This is the guide we walk clients through: first whether you need a dedicated store at all, then the trade-offs that actually decide it, the cost arithmetic at 1M, 10M and 100M vectors, and the operational work nobody puts in the benchmark.

The short version

  • Already on Postgres, under a few tens of millions of vectors, filters that join application data? Use pgvector. Revisit when a measured limit forces you to.
  • Already running OpenSearch or Elasticsearch for search? Add vectors there. You get BM25 and hybrid search in the same engine.
  • Large corpora queried rarely, or thousands of small tenants? Look at object-storage-first options (S3 Vectors, turbopuffer, LanceDB). Their cost curves are different.
  • High query rates at large scale, heavy continuous writes, or complex filtering, with no appetite for database work? A dedicated engine — Pinecone, Qdrant, Weaviate, Milvus/Zilliz.
  • Whatever you pick: build a golden evaluation set before you choose, and plan for re-embedding from day one.

First question: do you need a dedicated vector database?

Usually not at the start. The reasons to default to what you already run are not glamorous, which is why vendor comparisons skip them: one system to back up, monitor and secure; retrieval next to the data it filters on; transactions, foreign keys and row-level access control you already trust.

pgvector and pgvectorscale

pgvector (0.8.7 at the time of writing) supports HNSW and IVFFlat indexes, half-precision halfvec, binary and sparse vectors.1 Two details matter in practice. First, the indexable dimension limits: 2,000 for vector and 4,000 for halfvec — so a 3,072-dimension embedding has to be stored as halfvec or shortened before you can index it.1 Second, filtering. With approximate indexes, pgvector applies the WHERE clause after the index scan, so a selective filter can return fewer rows than you asked for. Since 0.8.0, iterative index scans keep scanning until enough rows pass the filter.1

-- Postgres with pgvector 0.8.x
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE chunks (
  id         bigserial PRIMARY KEY,
  tenant_id  uuid NOT NULL,
  doc_id     uuid NOT NULL,
  body       text NOT NULL,
  tsv        tsvector GENERATED ALWAYS AS (to_tsvector('english', body)) STORED,
  embedding  halfvec(1024) NOT NULL   -- half the memory of vector(1024)
);

CREATE INDEX ON chunks USING hnsw (embedding halfvec_cosine_ops)
  WITH (m = 16, ef_construction = 64);   -- pgvector defaults
CREATE INDEX ON chunks USING gin (tsv);
CREATE INDEX ON chunks (tenant_id);

-- Keep scanning when the tenant filter discards most candidates
SET hnsw.iterative_scan = 'relaxed_order';
SET hnsw.ef_search = 100;                -- default is 40; tune against recall

SELECT id, body
FROM chunks
WHERE tenant_id = $1
ORDER BY embedding <=> $2::halfvec
LIMIT 20;

pgvectorscale, from Timescale, adds a StreamingDiskANN index, Statistical Binary Quantization and label-based filtered search on top of pgvector, under the PostgreSQL licence.2 It is worth testing when your index no longer fits comfortably in memory. Its README publishes a benchmark against Pinecone; as with every vendor benchmark, run your own on your own data and filters.

The search engine you already run

OpenSearch and Elasticsearch both store dense vectors alongside their inverted indexes. Elasticsearch 9.x defaults new float vector fields to a quantized HNSW index (int8 or BBQ, depending on version and dimensions) and, from 9.4, to a disk-based BBQ index where the licence allows; it caps dimensions at 4,096.3 Both engines fuse BM25 and vector results with reciprocal rank fusion: Elasticsearch through an rrf retriever, OpenSearch through a score ranker processor added in 2.19.45 If your team already operates one of these, hybrid search is a configuration change, not a new system.

The landscape in late 2026

For the cases where an extension isn’t enough, the credible options fall into four groups. None are wrong choices; they optimise for different things.

GroupExamplesBest forWatch out for
Extend what you runpgvector, pgvectorscale, OpenSearch, ElasticsearchTeams with an existing database or search cluster; filters that join app dataMemory sizing, index build time, post-filtering behaviour
Dedicated enginesPinecone, Qdrant, Weaviate, Milvus / ZillizHigh query rates at scale, continuous writes, rich filtering, built-in hybrid searchAnother system to secure and sync; pricing models that punish one large namespace
Object-storage-firstS3 Vectors, turbopuffer, LanceDBLarge or many-tenant corpora with modest or bursty query ratesCold-query latency; fewer tuning knobs
Cloud-managed retrievalBedrock Knowledge Bases, Azure AI Search, Google Vector SearchTeams standardised on one cloud who want ingestion, chunking and retrieval managedLess control over chunking and ranking; harder to move later

Dedicated engines

Pinecone is fully managed and bills on storage, read units and write units, with a $50 monthly minimum on the Standard plan; it also sells hosted embedding and reranking models.6 Qdrant is open source with a managed cloud. Its quantization options are the most extensive we use, and its multitenancy guidance — one collection, a tenant payload index, large tenants promoted to dedicated shards — is sound.78 Weaviate ships hybrid search with a tunable vector/keyword balance and stores each tenant on its own shard, with inactive and offloaded states for tenants nobody is querying.910 Milvus (and Zilliz, its managed service) has the widest menu of index types, including DiskANN and GPU indexes.11

Object-storage-first

turbopuffer keeps data in object storage and caches hot namespaces on NVMe and in memory. Its own documentation reports a p50 of 874 ms for a cold query and 14 ms once cached, on 1M documents, and it supports BM25 alongside vectors.12 Pricing is based on storage, bytes written and data queried.13 LanceDB runs as an embedded open-source library over the Lance format, with an Enterprise tier for large deployments, and supports vector, full-text and hybrid search.14 Amazon S3 Vectors became generally available on 2 December 2025, with up to two billion vectors per index and around 100 ms latency for frequent queries (sub-second for infrequent ones).15 AWS describes it as best suited to infrequent-query workloads.16

Cloud-managed retrieval

Bedrock Knowledge Bases manages ingestion and retrieval over a vector store you choose: OpenSearch Serverless or managed clusters, S3 Vectors, Aurora PostgreSQL, Neptune Analytics, Pinecone, Redis Enterprise Cloud or MongoDB Atlas.16 Azure AI Search runs BM25 and vector queries in one request, merges them with RRF, and can apply a semantic reranker on top; it also underpins Microsoft’s Foundry IQ knowledge layer.17 Google’s Vector Search, now documented under the Gemini Enterprise Agent Platform (formerly Vertex AI), is built on ScaNN and supports dense, sparse and hybrid search with filtering.18

Decision flow

How we pick a vector store

Extend what you already run. Add a system only when a measured constraint forces it — and let the query pattern pick which kind.

DECISIONAlready run Postgres or OpenSearch?yesnoDECISIONFits one node, filters join app data?yesnoDECISIONSteady high QPS or heavy writes?yesnoExtend itpgvector · OpenSearch · ElasticDedicated enginePinecone · Qdrant · Weaviate · MilvusObject-storage-firstS3 Vectors · turbopuffer · LanceDBStandardised on one cloud and want ingestion managed too?Bedrock Knowledge Bases · Azure AI Search · Google Vector Search can sit over any branch

Hybrid search and reranking

If you take one thing from this article: do not ship dense-only retrieval without testing hybrid. Embeddings are good at meaning and bad at exact tokens — product codes, error numbers, names, clause references. BM25 is the reverse. The BEIR benchmark found BM25 a robust baseline that dense retrievers often failed to beat out of domain.19 Running both and fusing the results is cheap insurance.

Reciprocal rank fusion is the default way to combine them: each document scores the sum of 1 / (k + rank) across the result lists, so you never have to normalise BM25 scores against cosine similarities.20 Elasticsearch and OpenSearch both default k to 60.45 In Postgres you can write it yourself:

WITH dense AS (
  SELECT id, row_number() OVER (ORDER BY embedding <=> $2::halfvec) AS r
  FROM chunks
  WHERE tenant_id = $1
  ORDER BY embedding <=> $2::halfvec
  LIMIT 50
),
keyword AS (
  SELECT id, row_number() OVER (ORDER BY ts_rank_cd(tsv, q) DESC) AS r
  FROM chunks, websearch_to_tsquery('english', $3) AS q
  WHERE tenant_id = $1 AND tsv @@ q
  ORDER BY ts_rank_cd(tsv, q) DESC
  LIMIT 50
)
SELECT id, SUM(1.0 / (60 + r)) AS rrf_score
FROM (SELECT * FROM dense UNION ALL SELECT * FROM keyword) AS fused
GROUP BY id
ORDER BY rrf_score DESC
LIMIT 20;

Note that Postgres’ built-in ts_rank_cd is not BM25. It is good enough to catch exact-token matches, which is most of what hybrid search buys you; if keyword relevance itself matters, use a search engine or a BM25 extension.

Reranking is the second stage: retrieve 50–100 candidates cheaply, then score each query–passage pair with a cross-encoder and keep the top handful. In our experience it is the single biggest quality lever after hybrid search, and it is independent of the database. Hosted rerankers are priced per request — Pinecone lists $2 per 1,000 rerank requests for several models — so budget it like an LLM call.6

Filtering and multi-tenancy

Most production retrieval is filtered: by tenant, by permission, by document type, by date. Filtering is where approximate indexes behave least intuitively, because a graph index that finds the 40 nearest neighbours and then discards 39 of them on a filter returns one result. Every engine has an answer — iterative scans in pgvector, filter-aware graph traversal in the dedicated engines — but you have to test it with your real filter selectivity.

Milvus’ guidance is a useful rule of thumb: graph indexes win when filters remove less than about 85% of rows, and brute-force search is the accurate choice when they remove more than 98%.11 In Postgres the equivalent is to let a B-tree index on the filter column drive an exact search when the filter is very selective, and to use partial indexes or partitioning when there are few distinct filter values.1

Tenancy patternHow it worksUse when
Shared index + tenant filterOne index, tenant ID as a filtered field (Qdrant: is_tenant payload index)Many small tenants; the default in most engines8
Partition / shard per tenantEach tenant physically separate (Weaviate shards, Pinecone namespaces, Postgres partitions)Strong isolation, per-tenant deletion, idle tenants offloaded10
TieredSmall tenants share; large tenants promoted to dedicated shardsSkewed tenant sizes (Qdrant 1.16+)8
Index per tenantSeparate collection or database per tenantA handful of tenants with contractual isolation

Tenancy also drives cost on usage-priced services. Pinecone charges a query one read unit per GB of the namespace it searches, with a minimum of 0.25.21 Splitting one large namespace into per-tenant namespaces can cut read costs by orders of magnitude — we work through the numbers below.

Index types and quantization

Three index families cover almost everything you will meet.

IndexHow it worksStrengthsCosts
HNSW22Multi-layer proximity graph held in memoryHigh recall at low latency; the default nearly everywhereMemory-hungry; slow builds; deletes leave work for maintenance
IVFVectors clustered around centroids; search probes the nearest clustersFast builds, lower memory; suits large top-k11Recall depends on probes; centroids drift as data changes
DiskANNGraph stored on SSD with compressed vectors in memoryLarge indexes on modest RAM; stable latency112Needs fast disks; IOPS can become the bottleneck

Quantization is how you make any of them affordable at scale. Qdrant’s documentation gives typical ratios: scalar (float32 to int8) is about 4× smaller with usually under 1% error; binary is up to 32× smaller; product quantization reaches up to 64× at a larger accuracy cost.7 The trick that makes aggressive compression usable is oversampling and rescoring: fetch extra candidates with the compressed vectors, then re-rank them with the originals. Qdrant has this built in; pgvector documents the same pattern with a binary-quantized expression index.71 Our default: start with float16 or int8, measure recall against your golden set, and only go binary if memory forces it and rescoring recovers the loss.

Embedding models, dimensions and cost

The embedding model decides retrieval quality more than the database does, and its dimension count drives your memory bill linearly. Choose it on your own evaluation set, not a leaderboard: domain vocabulary, languages and document length all move the rankings.

Matryoshka embeddings make dimension a dial rather than a fixed cost. Models trained this way pack the most important information into the leading dimensions, so a truncated vector is still useful.23 OpenAI’s text-embedding-3 models accept a dimensions parameter (defaults 1,536 and 3,072), and Amazon Titan Text Embeddings V2 offers 1,024, 512 or 256.2416 A pattern we like: store shortened vectors in the index for the first pass, and rescore the candidates with full-length vectors kept in cheaper storage.

Check dimension limits before you commit. pgvector indexes up to 2,000 dimensions for vector, Elasticsearch and S3 Vectors cap at 4,096.1316

What it costs at 1M, 10M and 100M vectors

Vendor calculators make cost look either trivial or terrifying. The arithmetic below uses published prices and states its assumptions; substitute your own numbers.

Assumptions: 1,024-dimension float32 embeddings (4,096 bytes) plus about 1,000 bytes of ID and metadata per record — roughly 5.1 KB, following Pinecone’s storage formula of ID + metadata + dimensions × 4 bytes.21 One million queries a month. Pinecone Standard prices at the low end of its range: $0.33/GB-month storage and $16 per million read units.6 S3 Vectors storage at $0.06/GB-month (US East).25

1M vectors10M vectors100M vectors
Stored size (≈5.1 KB/record)5.1 GB51 GB510 GB
Raw vectors in RAM: float32 / float16 / binary4.1 / 2.0 / 0.13 GB41 / 20.5 / 1.3 GB410 / 205 / 13 GB
Pinecone storage / month≈ $1.70≈ $17≈ $168
Pinecone reads, one namespace (RU/query = GB)5.1M RU ≈ $8251M RU ≈ $816510M RU ≈ $8,160
Pinecone reads, 1,000 equal tenant namespaces (each query searches one)0.25M RU ≈ $40.25M RU ≈ $40.51M RU ≈ $8
S3 Vectors storage / month≈ $0.31≈ $3.06≈ $30.60
Re-embed corpus (500 tokens/chunk): 3-small / 3-large$10 / $65$100 / $650$1,000 / $6,500

Re-embedding uses OpenAI’s list prices of $0.02 and $0.13 per million tokens for text-embedding-3-small and -large.26 For S3 Vectors queries, AWS’s own worked example — 10M vectors across 40 indexes, 1M queries a month — totals $11.38 a month including storage, uploads and queries.25 The RAM row is raw vectors only; HNSW graph links add more on top, so treat it as a floor when sizing a self-hosted node.

Three things fall out of the table. Storage is rarely the problem; query pricing and RAM are. Tenancy design can matter more than vendor choice on usage-priced services. And re-embedding is cheap in API fees but expensive in engineering time, which is the next section.

Evaluating retrieval before you choose

Every vendor benchmark is run on someone else’s data with someone else’s filters. The only benchmark that counts is a golden set: a few hundred real queries, each labelled with the passages that should come back, ideally graded for relevance. Pull queries from logs or support tickets, not from the team’s imagination, and include the awkward ones — exact codes, negations, multi-hop questions.

Then track a small number of metrics on every change:

  • Recall@k — what share of the relevant passages appear in the top k. This is the metric for the retrieval stage, because the LLM cannot use what was never retrieved.
  • nDCG@10 — rewards putting the most relevant passages first. This is the metric for the reranker.
  • Latency at p95 under realistic filters, and recall of the approximate index against exact search on the same queries, so you know what the index itself is costing you.
import math

def recall_at_k(retrieved: list[str], relevant: set[str], k: int = 10) -> float:
    return len(set(retrieved[:k]) & relevant) / len(relevant)

def ndcg_at_k(retrieved: list[str], grades: dict[str, int], k: int = 10) -> float:
    # grades: passage_id -> relevance 0..3; unlisted passages count as 0
    dcg = sum(grades.get(p, 0) / math.log2(i + 2) for i, p in enumerate(retrieved[:k]))
    ideal = sorted(grades.values(), reverse=True)[:k]
    idcg = sum(g / math.log2(i + 2) for i, g in enumerate(ideal))
    return dcg / idcg if idcg else 0.0

With that harness in place, the database decision becomes an experiment: load the same corpus into two candidates, run the same queries with the same filters, and compare recall, latency and projected cost. It usually takes days, not weeks.

Operations: the part nobody benchmarks

Re-embedding on model change

Vectors from different embedding models are not comparable. When you upgrade the model — and you will — every vector must be regenerated. Design for it from the start: keep the source text and chunking parameters, record the model name and version on every row, and build the new index alongside the old one. Switch reads with an alias or a feature flag once the golden set confirms the new index is better, then retire the old one.

Updates and deletes

Documents change, permissions change, and deletion requests have deadlines. Graph indexes handle deletes by marking and cleaning up later, so heavy churn degrades recall and bloats storage until maintenance runs — vacuum in Postgres, compaction or optimisation in the dedicated engines. Key every chunk by its source document so you can replace a document’s chunks atomically, and test that a deleted document actually stops appearing in results.

Backups and disaster recovery

If vectors live in Postgres, your existing backups cover them. On a managed vector service, check what backup means and what it costs: Pinecone, for example, prices backups at $0.10/GB-month and restores at $0.15/GB.6 Because vectors can be regenerated from source text, some teams treat the index as a cache and back up only the source and metadata. That works only if you have measured how long a full rebuild takes.

Failure modes we see repeatedly

  • Dense-only retrieval that misses exact identifiers users type every day.
  • Filtered queries returning too few results because the index post-filters and nobody tested with a selective tenant.
  • Choosing on a vendor benchmark that used no filters and a different embedding model.
  • One giant namespace on a service that bills queries by namespace size.
  • No model version on vectors, so a partial re-embed silently mixes incompatible vectors.
  • Index sized to today’s data, swapping to disk six months later as the corpus grows.
  • Permissions checked after generation rather than enforced as a retrieval filter.

Checklist

  1. Estimate vectors per tenant in 18 months, and the query rate.
  2. Decide whether you can extend Postgres or your search engine before adding a system.
  3. Build a golden set of real, labelled queries before choosing anything.
  4. Test hybrid (BM25 + dense with RRF) and a reranker against dense-only.
  5. Test filtered queries at your most selective real filter.
  6. Pick the embedding model and dimension on your data; check index dimension limits.
  7. Start with float16 or int8; go further only with rescoring and measured recall.
  8. Design tenancy for isolation, deletion and query cost.
  9. Store model name and version on every vector; plan a side-by-side re-embed.
  10. Work through the cost arithmetic at 1×, 10× and 100× today’s volume.

The vector database matters less than the marketing suggests. Pick the simplest option that meets your measured constraints and spend the saved time on chunking, hybrid retrieval, reranking and evaluation. If you want a second pair of hands on that work, ForthClover’s agent engineering team does exactly this.

Sources

  1. pgvector README (v0.8.7): index types, dimension limits, iterative index scans, filtering, binary quantization — github.com/pgvector/pgvector
  2. Timescale, pgvectorscale README: StreamingDiskANN, Statistical Binary Quantization, label-based filtering — github.com/timescale/pgvectorscale
  3. Elastic, dense_vector field type: index_options and default quantized index types by version — www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector
  4. Elastic, Reciprocal rank fusion (rrf retriever) — www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion
  5. OpenSearch, Score ranker processor (RRF for hybrid queries, OpenSearch 2.19+) — docs.opensearch.org/latest/search-plugins/search-pipelines/score-ranker-processor/
  6. Pinecone pricing (Standard and Enterprise plans, storage, read/write units, rerank, backups) — www.pinecone.io/pricing/
  7. Qdrant documentation, Quantization (scalar, binary, product, TurboQuant; rescoring and oversampling) — qdrant.tech/documentation/guides/quantization/
  8. Qdrant documentation, Multitenancy (payload partitioning, is_tenant, tiered multitenancy) — qdrant.tech/documentation/guides/multiple-partitions/
  9. Weaviate documentation, Hybrid search (alpha, fusion methods) — docs.weaviate.io/weaviate/search/hybrid
  10. Weaviate documentation, Multi-tenancy (shard per tenant, tenant states) — docs.weaviate.io/weaviate/manage-collections/multi-tenancy
  11. Milvus documentation, Index explained (IVF, HNSW, DiskANN, GPU indexes; filter-ratio guidance) — milvus.io/docs/index-explained.md
  12. turbopuffer documentation, Architecture (object storage, NVMe cache, cold vs cached latency, BM25) — turbopuffer.com/docs/architecture
  13. turbopuffer pricing — turbopuffer.com/pricing
  14. LanceDB documentation (OSS embedded library, Enterprise, vector/full-text/hybrid search) — docs.lancedb.com/
  15. AWS, “Amazon S3 Vectors is now generally available with 40 times the scale of preview,” 2 Dec 2025 — aws.amazon.com/about-aws/whats-new/2025/12/amazon-s3-vectors-generally-available/
  16. AWS, Amazon Bedrock Knowledge Bases: prerequisites for your own vector store (supported stores, S3 Vectors notes, Aurora iterative scans) — docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html
  17. Microsoft Learn, Hybrid search overview — Azure AI Search (RRF, semantic ranker, Foundry IQ) — learn.microsoft.com/en-us/azure/search/hybrid-search-overview
  18. Google Cloud, Vector Search overview (Gemini Enterprise Agent Platform, formerly Vertex AI) — docs.cloud.google.com/vertex-ai/docs/vector-search/overview
  19. Thakur et al., “BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models,” NeurIPS 2021 — arxiv.org/abs/2104.08663
  20. Cormack, Clarke & Büttcher, “Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods,” SIGIR 2009 — cormack.uwaterloo.ca/cormacksigir09-rrf.pdf
  21. Pinecone documentation, Understanding cost (read units per GB of namespace, write units, storage formula) — docs.pinecone.io/guides/manage-cost/understanding-cost
  22. Malkov & Yashunin, “Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs,” 2016 — arxiv.org/abs/1603.09320
  23. Kusupati et al., “Matryoshka Representation Learning,” arXiv:2205.13147 — arxiv.org/abs/2205.13147
  24. OpenAI API documentation, Embeddings (text-embedding-3 models and the dimensions parameter) — developers.openai.com/api/docs/guides/embeddings
  25. Amazon S3 pricing — S3 Vectors (storage, PUT, query charges, pricing example 1) — aws.amazon.com/s3/pricing/
  26. OpenAI API pricing (embedding models) — developers.openai.com/api/docs/pricing

Product details and prices were checked against each primary source in October 2026. Prices vary by region and plan and change often; confirm current figures before budgeting.