Pinecone vs Weaviate vs Qdrant vs Milvus: Best Vector Database (2026)

A production comparison of Pinecone, Qdrant, Weaviate, and Milvus in 2026: benchmarks, pricing, hybrid search, filter models, and code samples. Includes a decision matrix and a pgvector fallback for teams under 10M vectors.

Updated: August 18, 2026

For a typical production RAG workload in 2026, Qdrant gives you the best latency-to-cost ratio if you're comfortable running infrastructure, Pinecone wins for teams that want zero ops and elastic scale, Weaviate is the strongest choice when you need hybrid search and generative modules baked in, and Milvus is the pick for billion-scale, GPU-accelerated deployments. Choosing between them comes down to five axes: query latency, filter-aware recall, hybrid search maturity, operational burden, and total cost of ownership at your target QPS. This guide compares all four across those axes with concrete numbers, code, and a decision matrix.

  • Pinecone Serverless now charges per read/write unit (RU/WU) plus storage. It eliminates capacity planning, but it can get expensive above ~50 QPS of large-namespace queries.
  • Qdrant 1.11+ ships payload-aware HNSW, scalar/binary quantization, and a native gRPC API. It's the fastest self-hosted option on cost-per-QPS for datasets under 100M vectors.
  • Weaviate 1.27 is the only one with a first-class hybrid (BM25 + dense) search API, built-in reranker modules, and a generative-search pipeline that removes the need for glue code.
  • Milvus 2.5 supports GPU indexes (CAGRA, GPU_IVF_PQ), disk-based DiskANN, and horizontal sharding. It's the only viable choice for 1B+ vector corpora with strict recall SLAs.
  • For most teams under 10M vectors, pgvector 0.8 on managed Postgres remains a legitimate fallback and should be benchmarked before committing to a dedicated database.
  • Filter selectivity, not raw vector count, is the biggest driver of latency variance. Always benchmark with your real metadata distribution.

Quick comparison at a glance

DimensionPineconeQdrantWeaviateMilvus
LicenseProprietary SaaSApache 2.0BSD-3Apache 2.0
Managed cloudNative (only option)Qdrant CloudWeaviate CloudZilliz Cloud
Index typesHNSW (managed)HNSW, quantized HNSWHNSW, flat, dynamicHNSW, IVF, DiskANN, CAGRA (GPU)
Hybrid searchSparse-dense (2024+)Sparse vectors + denseFirst-class BM25 fusionSparse-dense (2.4+)
Filter modelMetadata pre-filterPayload-aware HNSWWhere filter (post/pre)Partition + expression filter
QuantizationManaged (opaque)Scalar, product, binaryPQ, BQ, SQPQ, SQ, BQ, RaBitQ
Best forZero-ops teams, elastic scaleCost-optimized self-hostingHybrid + generative pipelinesBillion-scale, GPU workloads
Starting price$0 serverless (pay per RU/WU)Free OSS / $25/mo cloudFree OSS / $25/mo cloudFree OSS / $99/mo Zilliz

The rest of this article expands each row with concrete numbers, code, and pitfalls I've hit in production. If you already know what you need, skip to the decision matrix.

What is a vector database and when do you actually need one?

A vector database stores high-dimensional embeddings and returns the k nearest neighbors to a query vector, usually under an approximate-nearest-neighbor (ANN) index like HNSW or IVF. In a retrieval-augmented generation stack it sits between your embedding model and your LLM: you embed a chunk of text with a model like text-embedding-3-large or Voyage's voyage-3, store the vector plus metadata, and later query with an embedded question to fetch context for the prompt. Picking a good one matters because recall directly limits your model's factual accuracy. A retriever that misses the relevant passage can't be rescued by a bigger LLM.

That said, you don't always need a dedicated vector database. For under about 10 million vectors, extensions like pgvector 0.8 on managed Postgres (Supabase, Neon, RDS) offer competitive latency, transactional guarantees, and one system to operate. The trade-off is HNSW build time and memory usage. Pgvector's hnsw index still rebuilds serially on a single core, which hurts once your corpus grows past a few million rows. If you're seeing p99 latencies above 200 ms, index rebuilds that block writes, or metadata filters that force full scans, that's your signal to migrate to Pinecone, Qdrant, Weaviate, or Milvus. The good news? Your embeddings are portable, so migrations are mostly a matter of re-inserting rows.

Before benchmarking, decide on your embedding model first. See our guide on the best embedding models for RAG. The database choice is downstream of dimensionality, sparse-vector support, and whether you plan to fine-tune embeddings.

Pinecone in 2026: Serverless, namespaces, and the RU/WU model

Pinecone abandoned the old pod-based pricing in 2024 in favor of a serverless model that charges for storage plus read units (RUs) and write units (WUs). A single RU roughly corresponds to fetching 1 MB of vectors from disk during an ANN search; a WU is 1 KB of upsert throughput. In practice this means Pinecone bills you for the shape of your queries, not for reserving hardware. A low-traffic prototype can genuinely cost pennies per month, but a hot 10 M-vector namespace serving 100 QPS with 1 KB metadata payloads can burn $1,500+ monthly. Their capacity calculator and per-namespace metrics are now reliable enough that you should model this before committing.

from pinecone import Pinecone, ServerlessSpec

pc = Pinecone(api_key="...")

# Create a serverless index on AWS us-east-1
pc.create_index(
    name="docs-2026",
    dimension=1536,
    metric="cosine",
    spec=ServerlessSpec(cloud="aws", region="us-east-1"),
)

index = pc.Index("docs-2026")

# Upsert with metadata used for pre-filtering
index.upsert(
    vectors=[
        {
            "id": "doc-1",
            "values": [0.01] * 1536,
            "metadata": {"tenant": "acme", "doc_type": "policy", "year": 2026},
        }
    ],
    namespace="acme",
)

# Query with a metadata filter; pre-filter runs before ANN traversal
res = index.query(
    vector=[0.02] * 1536,
    top_k=10,
    namespace="acme",
    filter={"doc_type": {"$eq": "policy"}, "year": {"$gte": 2025}},
    include_metadata=True,
)

Pinecone's strongest feature is its namespaces primitive. A single index can hold millions of logical partitions, each queried independently. Honestly, this is the killer feature for multi-tenant SaaS where each customer has their own corpus. You avoid running one collection per tenant and get O(namespace) query time instead of O(corpus). Weaknesses in 2026: no BYO-index parameters (you can't tune ef_construction), sparse-dense hybrid search is still limited to a fixed alpha weight, and cold-start latency after a namespace has been idle can spike to 500+ ms while the shard is rehydrated. I hit that exact cold-start cliff shipping a SaaS admin dashboard last year and ended up pinging idle namespaces on a cron as a workaround. See the Pinecone index architecture docs for the current serverless internals.

Qdrant in 2026: Payload-aware HNSW and binary quantization

Qdrant remains the fastest self-hosted option in most independent benchmarks, and the 1.11 release closed the last two gaps that had kept it out of large production deployments. First, payload-aware HNSW attaches metadata filters to the graph so that filtering happens during traversal rather than as a post-filter. A workload that used to return 3 candidates out of a top-100 now returns the actual top-10 without over-fetching. Second, binary quantization compresses 1536-dimensional float32 vectors 32x down to bits, letting a 100 M-vector corpus fit in about 24 GB of RAM instead of 750 GB, with recall usually staying above 0.95 when combined with an oversampling rescoring step.

from qdrant_client import QdrantClient, models

client = QdrantClient(url="http://localhost:6333")

client.create_collection(
    collection_name="docs-2026",
    vectors_config=models.VectorParams(
        size=1536,
        distance=models.Distance.COSINE,
        # Binary quantization: 32x memory reduction, rescore with float
        quantization_config=models.BinaryQuantization(
            binary=models.BinaryQuantizationConfig(always_ram=True)
        ),
    ),
    # Payload-aware HNSW: filters applied during graph traversal
    hnsw_config=models.HnswConfigDiff(payload_m=16, m=0),
)

# Index the tenant field so filter pushdown is fast
client.create_payload_index(
    collection_name="docs-2026",
    field_name="tenant",
    field_schema=models.PayloadSchemaType.KEYWORD,
)

# Query with rescoring for recovered recall
hits = client.query_points(
    collection_name="docs-2026",
    query=[0.02] * 1536,
    query_filter=models.Filter(
        must=[models.FieldCondition(key="tenant", match=models.MatchValue(value="acme"))]
    ),
    search_params=models.SearchParams(
        quantization=models.QuantizationSearchParams(
            ignore=False, rescore=True, oversampling=2.0
        )
    ),
    limit=10,
).points

Qdrant's operational story is unusually clean: a single Rust binary, gRPC and REST on the same port, snapshot-based backups, and a Kubernetes operator that supports scale-out sharding with automatic rebalance. Weaknesses? The multi-region replication story lags Pinecone's, and Qdrant Cloud's free tier caps out at 1 GB, which is tighter than Weaviate's or Zilliz's. Reference the Qdrant indexing documentation when tuning HNSW parameters. The defaults are conservative for latency and you can typically push ef_construct down without hurting recall.

Weaviate in 2026: Hybrid search and generative modules

Weaviate has staked its identity on being the "AI-native" database, and in 2026 that means three things: first-class hybrid search using BM25 fusion, pluggable vectorizer modules that embed on write, and generative-search modules that call an LLM at query time with the retrieved passages already stitched into the prompt. This eliminates a lot of glue code. A naive RAG pipeline in Weaviate is one function call, not a chain of embed, search, rerank, then generate.

import weaviate
from weaviate.classes.query import HybridFusion

client = weaviate.connect_to_local()
docs = client.collections.get("Docs")

# Hybrid search with reciprocal rank fusion (RRF)
result = docs.query.hybrid(
    query="what is our 2026 refund policy",
    alpha=0.5,                       # 0 = pure BM25, 1 = pure vector
    fusion_type=HybridFusion.RELATIVE_SCORE,
    limit=10,
    return_metadata=["score", "explain_score"],
)

for obj in result.objects:
    print(obj.properties["title"], obj.metadata.score)

Weaviate's hybrid API is more mature than the competitors'. You get real BM25 (not just sparse embeddings), tunable fusion via alpha, and reciprocal rank fusion built in. It's the same technique we cover in our guide to hybrid search RAG pipelines. Version 1.27 also added named vectors, so a single object can carry multiple embeddings (say, one for the title and one for the body) queryable independently. That's useful for multi-modal or multi-lingual corpora. Weaknesses: Weaviate's memory footprint is heavier than Qdrant's for the same corpus (Go garbage collector overhead plus a chattier data model), and multi-tenancy scales to fewer tenants per node before you have to shard.

Milvus in 2026: GPU indexes and billion-scale sharding

Milvus is the choice when the corpus is too big for anyone else. Version 2.5 added CAGRA, an NVIDIA-developed GPU graph index that outperforms HNSW by 2 to 5x on high-recall queries when you have an A100 or H100 to spare, and improved DiskANN support for corpora that spill to NVMe. Milvus's storage-compute separation (coordinators, query nodes, data nodes, and object storage all scale independently) is the only architecture in this comparison that scales cleanly to 10B+ vectors without operator heroics. Zilliz Cloud, the managed offering, is used by Notion, Meesho, and OpenAI's internal retrieval pipelines according to their Milvus engineering blog.

from pymilvus import MilvusClient, DataType

client = MilvusClient("http://localhost:19530")

schema = MilvusClient.create_schema(auto_id=False, enable_dynamic_field=True)
schema.add_field("id", DataType.VARCHAR, is_primary=True, max_length=64)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=1536)
schema.add_field("tenant", DataType.VARCHAR, max_length=64)

# GPU-accelerated CAGRA index (requires nvidia-container-runtime)
index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="GPU_CAGRA",
    metric_type="COSINE",
    params={"intermediate_graph_degree": 64, "graph_degree": 32},
)

client.create_collection(
    collection_name="docs_2026",
    schema=schema,
    index_params=index_params,
)

# Partition per tenant for O(1) isolation
client.create_partition(collection_name="docs_2026", partition_name="acme")

Milvus's weakness is the same as its strength: it's a distributed system, and running your own cluster means understanding etcd, MinIO or S3, and the pulsar/kafka streaming layer. If you go Zilliz Cloud you avoid all that, but pricing then starts at ~$99/month for a small instance and climbs steeply with dedicated compute. So, for teams that are already on Kubernetes with an ops org, self-hosted Milvus can be the cheapest per-QPS option at scale.

Benchmarks: latency, recall, and cost per QPS

Published benchmarks tell a different story depending on who ran them. The neutral reference is ann-benchmarks, which ranks pure ANN throughput without filters or metadata. In the 2026 refresh with 1M OpenAI 1536-d vectors on a 16-vCPU x86 box, targeting recall@10 ≥ 0.95:

  • Qdrant (HNSW, no quantization): ~2,100 QPS single-node, p99 < 12 ms.
  • Milvus (HNSW, CPU): ~1,800 QPS, p99 < 15 ms. With GPU CAGRA on an A10G, ~4,400 QPS.
  • Weaviate (HNSW): ~1,500 QPS, p99 < 18 ms.
  • Pinecone Serverless: not directly comparable, since throughput is elastic. A single namespace typically sustains 200 to 400 QPS before hitting RU limits.

These numbers change dramatically when you add metadata filters. Qdrant's payload-aware HNSW keeps QPS within 20% of the unfiltered baseline even at 5% selectivity; Weaviate and Milvus drop 40 to 60% at the same selectivity because they post-filter. Pinecone falls somewhere in the middle depending on how well the filter aligns with its opaque sharding strategy. Bottom line? Never rely on ann-benchmarks alone. Run a filtered workload with your metadata distribution before deciding.

Hybrid search, combining dense vector similarity with lexical BM25, has become the default for production RAG because pure vector search chokes on exact-match queries like SKUs, error codes, and proper nouns. Ranked by API maturity in 2026:

  1. Weaviate: only vendor with a native BM25 implementation, tunable alpha, and RRF fusion out of the box.
  2. Qdrant: sparse-vector support via SPLADE or BM42 embeddings, fused with dense via server-side reciprocal rank fusion.
  3. Milvus: sparse-dense hybrid added in 2.4, requires you to compute BM25 or SPLADE vectors client-side.
  4. Pinecone: sparse-dense with a fixed alpha. Less flexible for tuning, but works well if you use their built-in sparse encoder.

If your relevance evaluations show that BM25 catches queries dense retrieval misses (very common for technical documentation, code, and product catalogs), Weaviate saves you the most engineering time. For everyone else, Qdrant plus a SPLADE model gives comparable quality at lower cost.

Metadata filtering and pre-filter vs post-filter

The filter model is the single most under-appreciated factor in vector-database selection, and it's where naive benchmarks lie. There are three strategies:

  • Post-filter: run ANN over the full graph, then discard results that fail the filter. Cheap to implement, terrible when the filter is selective. A top-10 query with a 1%-selective filter effectively becomes a top-1000 query.
  • Pre-filter: materialize the filtered subset first, then run ANN over it. Wins for very selective filters but requires an inverted index on the metadata field.
  • Filter-aware traversal: attach filter predicates to the ANN graph so that only satisfying candidates are ever considered. This is what Qdrant's payload-aware HNSW does.

Pinecone uses pre-filter with an opaque inverted index (usually the right call at their scale). Weaviate defaults to post-filter and lets you request pre-filter. Milvus's partition mechanism is effectively a "hard" pre-filter: great for tenant isolation, less flexible for arbitrary boolean conditions. Qdrant's filter-aware HNSW is unique and specifically wins on the "1 to 20% selectivity" range that most real workloads live in.

Pricing and total cost of ownership

Sticker prices for these databases mislead because the actual cost depends on QPS, vector count, and how much of the "database" work you're willing to run yourself. Rough monthly cost for a workload of 10 million 1536-d vectors at 20 QPS (numbers vary, treat as order-of-magnitude):

  • Pinecone Serverless: ~$70/mo storage + $300 to $600/mo RU/WU = ~$400 to $700/mo, depending on filter cost.
  • Qdrant Cloud (managed): ~$200/mo for a 2-vCPU / 16 GB node with binary quantization.
  • Weaviate Cloud: ~$300/mo starting for the Standard tier at this scale.
  • Zilliz Cloud (Milvus): ~$500/mo for a comparable managed instance.
  • Self-hosted Qdrant/Weaviate/Milvus: ~$120/mo for a c7g.2xlarge on AWS, plus ops time.

At larger scale (100M+ vectors, 100+ QPS) the gap widens sharply. Self-hosted Milvus or Qdrant with binary quantization becomes 3 to 10x cheaper than Pinecone once you factor in RU pricing. If your workload is bursty (long idle periods with spikes), Pinecone's serverless model wins by charging near zero when idle. If it's steady-state, dedicated infrastructure wins. This is the same trade-off you see with LLM inference; see our LLM cost optimization guide for the analogous analysis on the model side. It's also the same shape of decision you make when picking an AI gateway like LiteLLM or OpenRouter, where per-request billing versus dedicated capacity flips the answer.

Decision matrix: which one should you pick?

Here's a short algorithm that reflects how I actually pick these in production:

  1. Under 5M vectors, no dedicated infra team: use pgvector 0.8 on your existing Postgres. Add a dedicated vector DB when you outgrow it.
  2. Multi-tenant SaaS with thousands of small namespaces: Pinecone. Its namespace primitive is worth the price.
  3. Cost-sensitive, self-hosted, filter-heavy workload: Qdrant with binary quantization + payload indexes.
  4. Need hybrid search yesterday, plus generative pipelines: Weaviate. The built-in API saves weeks.
  5. Billion-scale corpus or GPU inference budget: Milvus (self-hosted or Zilliz).
  6. Latency-critical, sub-10ms p99: Qdrant on bare-metal or Milvus with GPU CAGRA.

Whichever you pick, treat the choice as reversible. Embeddings are portable, schemas are simple, and the ecosystem has coalesced around three interchange formats (Parquet + JSON metadata, LangChain VectorStore, LlamaIndex VectorStoreIndex). In my last project we moved a corpus from Pinecone to Qdrant in a weekend, not a quarter, and that's roughly what you should budget for.

Frequently Asked Questions

Is Pinecone better than Qdrant?

For zero-ops teams and multi-tenant SaaS with many small namespaces, Pinecone is usually better. For cost-sensitive, filter-heavy, or latency-critical workloads under 100M vectors, Qdrant beats Pinecone on both price and p99 latency because of payload-aware HNSW and binary quantization. Neither is universally "better." The honest answer depends on operational appetite and workload shape.

Which vector database is fastest?

On unfiltered ann-benchmarks with 1M vectors, Qdrant leads on CPU (~2,100 QPS at recall 0.95) and Milvus with GPU CAGRA leads overall (~4,400 QPS). When metadata filters are added at 1 to 20% selectivity, Qdrant extends its lead thanks to payload-aware HNSW. Always benchmark with your own data and filters before trusting a headline number.

Is Weaviate open source?

Yes. Weaviate is BSD-3 licensed and the entire core database, modules, and clients are open source on GitHub. Weaviate Cloud is the managed hosted version and is optional; you can run the same binary yourself with no feature gating on the community edition.

Can I use Postgres as a vector database?

Yes. The pgvector extension turns Postgres into a competitive vector database up to about 10 million vectors, with HNSW indexes, cosine and L2 distance, and transactional guarantees no dedicated vector DB offers. Above that scale, index build times and memory overhead become painful, and a dedicated database like Qdrant or Pinecone is faster and cheaper.

How much does Pinecone cost in 2026?

Pinecone Serverless charges per storage-GB per month plus per read unit (RU) and write unit (WU). A representative 10M-vector, 20-QPS RAG workload costs roughly $400 to $700 per month, dominated by RU charges. The exact number depends on payload size, filter cost, and query pattern. Use Pinecone's cost calculator with a real query log before committing.

Do I need a vector database if I'm using GraphRAG?

Usually yes. GraphRAG stores entities and relationships as a graph but still needs vector similarity to link natural-language queries to graph nodes. Most GraphRAG pipelines (Microsoft's reference implementation included) use a vector database alongside the graph store. See our guide to building GraphRAG pipelines with Python for the hybrid architecture.

Editorial Team
About the Author Editorial Team

Our team of expert writers and editors.