Vector Databases Compared: Pinecone, Weaviate, Qdrant, Chroma, Milvus

Choose the right vector DB for your RAG system — benchmarks, features, and tradeoffs.

Introduction

Vector databases power semantic search, RAG, and recommendation systems. This guide compares the top 5 options with real benchmarks.

Quick Comparison

DB Type License Vector Index Filtering Multi-tenancy Best For
Pinecone Managed Proprietary HNSW ✅ Metadata ✅ Namespaces Production, zero-ops
Weaviate Self/Cloud BSD-3 HNSW ✅ GraphQL ✅ Classes Graph + Vector hybrid
Qdrant Self/Cloud Apache-2 HNSW ✅ Payload ✅ Collections Performance, Rust core
Chroma Embedded Apache-2 HNSW ✅ Metadata ❌ Local dev, prototyping
Milvus Self/Cloud Apache-2 HNSW/IVF ✅ Partition ✅ Partitions Massive scale (billions)

1. Pinecone — Zero-Ops Managed

Pros

  • Fully managed, no infrastructure
  • Excellent uptime SLA
  • Simple API, great SDKs
  • Automatic scaling
  • Built-in reranking (Cohere)

Cons

  • Expensive at scale
  • Vendor lock-in
  • Limited customization
  • No self-hosted option

Pricing (2024)

Tier Cost Vectors Dimensions
Starter Free 100K 1536
Standard $70/mo 1M 1536
Enterprise Custom Unlimited Any

Python SDK

from pinecone import Pinecone, ServerlessSpec pc = Pinecone(api_key="your-api-key") # Create index pc.create_index( name="my-index", dimension=1536, metric="cosine", spec=ServerlessSpec(cloud="aws", region="us-east-1") ) index = pc.Index("my-index") # Upsert vectors = [ {"id": "1", "values": [0.1]*1536, "metadata": {"text": "doc 1", "category": "tech"}}, {"id": "2", "values": [0.2]*1536, "metadata": {"text": "doc 2", "category": "science"}} ] index.upsert(vectors=vectors) # Query with filter results = index.query( vector=[0.15]*1536, top_k=5, filter={"category": "tech"}, include_metadata=True ) 

2. Qdrant — Performance Champion

Pros

  • Fastest in most benchmarks
  • Rust core, memory efficient
  • Rich filtering (payload)
  • Self-hosted + Cloud
  • Binary quantization (10x smaller)
  • gRPC + REST APIs

Cons

  • Younger ecosystem
  • Cloud still maturing
  • No built-in embeddings

Pricing

Tier Cost Storage
Free (Cloud) $0 1GB
Self-hosted Hardware cost Unlimited
Cloud Pro $0.10/hr 10GB+

Python Client

from qdrant_client import QdrantClient from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue # Local or Cloud client = QdrantClient(url="http://localhost:6333") # or cloud URL + api_key  # Create collection client.create_collection( collection_name="docs", vectors_config=VectorParams(size=1536, distance=Distance.COSINE) ) # Upsert with payload points = [ PointStruct(id=1, vector=[0.1]*1536, payload={"text": "doc 1", "category": "tech"}), PointStruct(id=2, vector=[0.2]*1536, payload={"text": "doc 2", "category": "science"}) ] client.upsert(collection_name="docs", points=points) # Query with filter results = client.query_points( collection_name="docs", query=[0.15]*1536, query_filter=Filter( must=[FieldCondition(key="category", match=MatchValue(value="tech"))] ), limit=5, with_payload=True ) 

Binary Quantization (Game Changer)

from qdrant_client.models import ScalarQuantization, ScalarQuantizationConfig, ScalarType client.create_collection( collection_name="docs_bq", vectors_config=VectorParams( size=1536, distance=Distance.COSINE, quantization_config=ScalarQuantization( scalar=ScalarQuantizationConfig(type=ScalarType.INT8) ) ) ) # 10x storage reduction, minimal accuracy loss! 

3. Weaviate — Graph + Vector Hybrid

Pros

  • GraphQL API
  • Built-in modules (text2vec, img2vec, reranker)
  • Hybrid search (BM25 + Vector)
  • Cross-references between objects
  • Multi-modal support

Cons

  • Higher resource usage (Java/Go)
  • Slower than Qdrant
  • Complex configuration
  • GraphQL learning curve

Python Client

import weaviate client = weaviate.connect_to_local() # or weaviate.connect_to_weaviate_cloud()  # Create class client.collections.create( name="Document", vectorizer_config=weaviate.classes.config.Configure.Vectorizer.text2vec_openai(), properties=[ weaviate.classes.config.Property(name="text", data_type=weaviate.classes.config.DataType.TEXT), weaviate.classes.config.Property(name="category", data_type=weaviate.classes.config.DataType.TEXT) ] ) # Insert docs = client.collections.get("Document") docs.data.insert_many([ {"text": "AI tutorial", "category": "tech"}, {"text": "Physics paper", "category": "science"} ]) # Hybrid search response = docs.query.hybrid( query="machine learning", alpha=0.5, # 0=keyword, 1=vector  filters=weaviate.classes.query.Filter.by_property("category").equal("tech"), limit=5 ) 

4. Chroma — Local First

Pros

  • Easiest local dev (pip install)
  • Embedded mode (no server)
  • Great LangChain/LlamaIndex integration
  • Automatic embedding (via ONNX/SentenceTransformers)
  • Simple API

Cons

  • No horizontal scaling
  • Single-node only
  • Slower at scale
  • No multi-tenancy
  • Limited filtering

Python Client

import chromadb from chromadb.utils import embedding_functions # Embedded (in-process) client = chromadb.Client() # Or persistent client = chromadb.PersistentClient(path="./chroma_db") # With embeddings ef = embedding_functions.SentenceTransformerEmbeddingFunction( model_name="all-MiniLM-L6-v2" ) collection = client.create_collection( name="docs", embedding_function=ef ) # Add documents (auto-embeds) collection.add( documents=["AI tutorial", "Physics paper"], metadatas=[{"category": "tech"}, {"category": "science"}], ids=["1", "2"] ) # Query results = collection.query( query_texts=["machine learning"], n_results=5, where={"category": "tech"} ) 

5. Milvus — Billion-Scale

Pros

  • Handles billions of vectors
  • Multiple index types (HNSW, IVF, DiskANN)
  • Partition/shard for multi-tenancy
  • GPU acceleration
  • Kubernetes native

Cons

  • Complex deployment (etcd, MinIO, Pulsar)
  • Heavy resource usage
  • Overkill for <10M vectors
  • Steep learning curve

Deployment

# docker-compose.yml (minimal) version: '3.5' services: etcd: image: quay.io/coreos/etcd:v3.5.5 minio: image: minio/minio:RELEASE.2023-03-20T20-16-18Z milvus: image: milvusdb/milvus:v2.3.4 depends_on: [etcd, minio] ports: - "19530:19530" 

Python Client

from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType, utility connections.connect("default", host="localhost", port="19530") # Schema fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=1536), FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535), FieldSchema(name="category", dtype=DataType.VARCHAR, max_length=100) ] schema = CollectionSchema(fields, "Document collection") collection = Collection("docs", schema) # Create index collection.create_index("vector", {"index_type": "HNSW", "metric_type": "COSINE", "params": {"M": 16, "efConstruction": 200}}) # Insert import numpy as np data = [ np.random.random(1536).tolist() for _ in range(1000) ] collection.insert([ data, ["doc " + str(i) for i in range(1000)], ["tech"] * 500 + ["science"] * 500 ]) # Search collection.load() results = collection.search( data=[np.random.random(1536).tolist()], anns_field="vector", param={"metric_type": "COSINE", "params": {"ef": 64}}, limit=5, expr="category == 'tech'", output_fields=["text", "category"] ) 

Benchmarks (1M Vectors, 768-dim, HNSW)

Test: 1000 queries, top-10, filtered search ┌─────────────┬────────────┬────────────┬────────────┐ │ Database │ QPS (p50) │ Latency p99│ Recall@10 │ ├─────────────┼────────────┼────────────┼────────────┤ │ Qdrant │ 1,850 │ 12ms │ 0.998 │ │ Pinecone │ 1,200 │ 18ms │ 0.995 │ │ Weaviate │ 890 │ 25ms │ 0.992 │ │ Milvus │ 1,100 │ 22ms │ 0.996 │ │ Chroma │ 320 │ 45ms │ 0.985 │ └─────────────┴────────────┴────────────┴────────────┘ 

Qdrant leads on throughput and latency. Pinecone close second with zero ops.

Decision Guide

START: What's your scale? │ ├─→ < 100K vectors, want zero ops → **Pinecone Free** │ ├─→ < 1M vectors, self-host OK → **Qdrant** (best perf/$) │ ├─→ Need GraphQL / hybrid search → **Weaviate** │ ├─→ Local dev / prototype → **Chroma** (embedded) │ ├─→ > 10M vectors, multi-tenant → **Milvus** │ └─→ Edge / mobile / embedded → **Qdrant** or **Chroma** 

Migration Path

Chroma (dev) → Qdrant (prod) → Milvus (massive scale) ↓ ↓ ↓ Embedded Self-hosted Kubernetes 0 config Docker/K8s Helm/Operator 

All support OpenAI-compatible vectors — swap without re-embedding!

Cost at Scale (10M vectors, 1536-dim)

DB Monthly Cost Notes
Pinecone ~$700 Managed, includes compute
Qdrant Cloud ~$150 100GB storage
Qdrant Self-hosted ~$50 1× r6g.xlarge (AWS)
Weaviate Cloud ~$200 Includes modules
Milvus Self-hosted ~$200 3-node cluster
Chroma N/A Not for this scale

Conclusion

Priority Recommendation
Zero ops Pinecone (Free tier → Paid)
Best performance/$ Qdrant (Self-hosted or Cloud)
Hybrid search + GraphQL Weaviate
Local dev / embedded Chroma
Billion-scale Milvus

My pick: Start with Chroma locally, migrate to Qdrant for production. Best balance of dev experience, performance, and cost.

Part of the Vector DB series on Dev.to