Vector Databases for AI Apps: Pinecone vs Weaviate vs Qdrant
Complete comparison of managed and self-hosted vector databases for RAG and semantic search.
Introduction
Vector databases are essential for Retrieval-Augmented Generation (RAG), semantic search, and recommendation systems. This guide compares the top options for production AI applications.
What is a Vector Database?
Vector databases store and query high-dimensional embeddings (vectors) efficiently. Unlike traditional databases, they specialize in:
- Similarity search (ANN - Approximate Nearest Neighbors)
- Metadata filtering combined with vector search
- Scalable to millions/billions of vectors
Quick Comparison
| Feature | Pinecone | Weaviate | Qdrant |
|---|---|---|---|
| Type | Managed cloud | Self-hosted / Cloud | Self-hosted / Cloud |
| Free Tier | 100k vectors | Unlimited (self-hosted) | 1M vectors (cloud) |
| Query Speed | Excellent | Very Good | Excellent |
| Filtering | Metadata | GraphQL + SQL-like | Payload filtering |
| Multi-tenancy | Built-in | Built-in | Built-in |
| Ease of Setup | Easiest | Moderate | Easy |
| Language Clients | Python, JS, Go, Java | Python, JS, Go, Java | Python, JS, Rust, Go |
Pinecone: Fully Managed Simplicity
import os
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key=os.getenv("PINECONE_API_KEY"))
# Create index
index_name = "ai-docs"
if index_name not in pc.list_indexes().names():
pc.create_index(
name=index_name,
dimension=1536, # OpenAI ada-002
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
index = pc.Index(index_name)
# Upsert vectors
vectors = [
("doc-1", [0.1]*1536, {"title": "AI Guide", "category": "tutorial"}),
("doc-2", [0.2]*1536, {"title": "ML Basics", "category": "intro"})
]
index.upsert(vectors=vectors)
# Query with metadata filter
results = index.query(
vector=[0.15]*1536,
top_k=5,
filter={"category": "tutorial"},
include_metadata=True
)
Pros: Zero ops, auto-scaling, excellent SDK
Cons: Costly at scale, vendor lock-in
Weaviate: GraphQL + Hybrid Search
import weaviate
import os
client = weaviate.connect_to_weaviate_cloud(
cluster_url=os.getenv("WEAVIATE_URL"),
auth_credentials=weaviate.AuthApiKey(os.getenv("WEAVIATE_API_KEY"))
)
# Schema
client.collections.create(
name="Document",
properties=[
weaviate.classes.config.Property(name="title", data_type=weaviate.classes.config.DataType.TEXT),
weaviate.classes.config.Property(name="content", data_type=weaviate.classes.config.DataType.TEXT),
weaviate.classes.config.Property(name="category", data_type=weaviate.classes.config.DataType.TEXT)
],
vectorizer_config=weaviate.classes.config.Configure.Vectorizer.text2vec_openai()
)
# Insert
collection = client.collections.get("Document")
collection.data.insert({
"title": "RAG Tutorial",
"content": "Retrieval-Augmented Generation...",
"category": "tutorial"
})
# Hybrid search (vector + keyword)
results = collection.query.hybrid(
query="vector database tutorial",
alpha=0.5, # 0=keyword, 1=vector
filters=weaviate.classes.query.Filter.by_property("category").equal("tutorial"),
limit=5
)
Pros: Hybrid search, GraphQL, modular architecture
Cons: More complex setup, resource intensive
Qdrant: High Performance, Rust-Powered
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct, Filter, FieldCondition, MatchValue
import os
client = QdrantClient(
url=os.getenv("QDRANT_URL"),
api_key=os.getenv("QDRANT_API_KEY")
)
# Create collection
client.create_collection(
collection_name="documents",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)
# Upsert with payload
points = [
PointStruct(id=1, vector=[0.1]*1536, payload={"title": "AI Guide", "category": "tutorial"}),
PointStruct(id=2, vector=[0.2]*1536, payload={"title": "ML Basics", "category": "intro"})
]
client.upsert(collection_name="documents", points=points)
# Query with payload filtering
results = client.query_points(
collection_name="documents",
query=[0.15]*1536,
query_filter=Filter(
must=[FieldCondition(key="category", match=MatchValue(value="tutorial"))]
),
limit=5,
with_payload=True
)
Pros: Fastest, binary quantization, rich filtering, self-hostable
Cons: Younger ecosystem, fewer integrations
Self-Hosted Quick Start
Weaviate (Docker)
docker run -d -p 8080:8080 \
-e QUERY_DEFAULTS_LIMIT=25 \
-e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
-e DEFAULT_VECTORIZER_MODULE=text2vec-openai \
-e ENABLE_MODULES=text2vec-openai \
cr.weaviate.io/semitechnologies/weaviate:1.25.0
Qdrant (Docker)
docker run -d -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant
RAG Pipeline Example (Any DB)
import os
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
# or use OpenRouter: base_url="https://openrouter.ai/api/v1"
def get_embedding(text: str) -> list:
response = client.embeddings.create(
model="text-embedding-3-small", # 1536 dims
input=text
)
return response.data[0].embedding
def rag_query(question: str, vector_db, collection: str = "documents") -> str:
# 1. Embed question
query_vector = get_embedding(question)
# 2. Search vector DB (adapt to your DB)
results = vector_db.query(vector=query_vector, top_k=3)
# 3. Build context
context = "\n\n".join([r.metadata.get("content", "") for r in results])
# 4. Generate answer
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Answer using only the provided context."},
{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {question}"}
],
temperature=0.1
)
return response.choices[0].message.content
Cost Comparison (1M vectors, 1536 dims)
| Provider | Monthly Cost | Notes |
|---|---|---|
| Pinecone (starter) | ~$70 | Managed, auto-scales |
| Weaviate Cloud | ~$50 | Managed, includes vectorizer |
| Qdrant Cloud | ~$30 | Best price/performance |
| Self-hosted (VPS) | $10-20 | 4GB RAM VPS, full control |
Recommendation by Scenario
| Scenario | Choose |
|---|---|
| Zero DevOps, quick start | Pinecone |
| Hybrid search (keyword + vector) | Weaviate |
| Maximum performance, cost-sensitive | Qdrant |
| Full control, on-premise | Qdrant / Weaviate self-hosted |
| GraphQL-first stack | Weaviate |
| Rust/Go backend | Qdrant |
Free Tier Limits
| Provider | Vectors | Dimensions | Requests |
|---|---|---|---|
| Pinecone | 100,000 | Up to 1536 | Unlimited |
| Weaviate Cloud | 10M objects | Any | 1M/month |
| Qdrant Cloud | 1,000,000 | Any | Generous |
| Self-hosted | Unlimited | Unlimited | Hardware limit |
Conclusion
- Start with Pinecone for fastest time-to-production
- Switch to Qdrant when scaling beyond free tier or need max performance
- Choose Weaviate if hybrid search (keyword + vector) is critical
- Self-host Qdrant for lowest cost at scale
All three handle production RAG workloads well. The choice depends on your team's expertise, budget, and specific search requirements.
Part of the Vector Database series on Dev.to
Top comments (0)