Vector Database Guide: Pinecone, Weaviate, Chroma, and pgvector Compared
โก Quick Answer
Vector database guide 2026 โ compare Pinecone, Weaviate, Chroma, pgvector and Qdrant by features, performance, cost, and use cases for production AI applications.
Get more content like this on Telegram!
Daily AI tips, notes & resources โ free
Advertisement
Vector Database Guide: Pinecone, Weaviate, Chroma, and pgvector Compared
A vector database stores embeddings and finds the nearest ones to a query vector in milliseconds, even across billions of entries. A real migration path shows why the choice matters: a first production RAG system built on Chroma got too slow for its dataset by month three, moved to Pinecone, and six months later was paying $400/month for what PostgreSQL with pgvector could have handled for $20.
Every vector database has a sweet spot. Knowing the tradeoffs before committing to one saves that kind of costly detour. This guide covers the major options with honest assessments of where each wins and where it doesn't.
The Vector Database Landscape
Vector databases split into five categories by how much operational overhead they ask of you โ managed cloud asks for none, self-hosted asks for the most control.
- Managed cloud (zero ops) โ Pinecone is the most mature managed offering; Weaviate Cloud is managed Weaviate.
- Self-hosted open-source โ Qdrant (Rust-based, excellent performance), Weaviate (full-featured, multimodal), Milvus (enterprise-grade, complex but scalable).
- Embedded, no separate server โ Chroma (Python-first, great for development), LanceDB (columnar storage, good for local use).
- PostgreSQL extensions โ pgvector adds vector search to an existing Postgres instance; pg_embedding is an alternative.
- Search platforms with vector support โ Elasticsearch and OpenSearch combine full-text and vector search natively.
Comparison Matrix
| Database | Type | Scale | Hybrid Search | Setup | Cost |
|---|---|---|---|---|---|
| Pinecone | Managed | 10M-1B+ | โ | Minutes | $70+/mo |
| Weaviate Cloud | Managed | 1M-100M+ | โ | Minutes | $0-$25+/mo |
| Qdrant Cloud | Managed | 1M-100M | โ | Minutes | $0-$50+/mo |
| Chroma | Embedded | <1M | โ | Seconds | Free |
| pgvector | Extension | <10M | Via PostgreSQL | Minutes | Existing DB |
| Qdrant (self-host) | Self-hosted | 1M-1B | โ | 1 hour | Infra cost |
| Weaviate (self-host) | Self-hosted | 1M-1B | โ | 1-2 hours | Infra cost |
Chroma: Development Default
Chroma runs in-process with zero setup, making it the fastest way to prototype a RAG pipeline before committing to infrastructure.
# pip install chromadb
import chromadb
from chromadb.utils import embedding_functions
# In-memory client (lost when process ends)
client = chromadb.Client()
# Persistent client
client = chromadb.PersistentClient(path="./chroma_db")
# Create collection with embedding function
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="your-key",
model_name="text-embedding-3-small"
)
collection = client.get_or_create_collection(
name="documents",
embedding_function=openai_ef,
metadata={"hnsw:space": "cosine"} # Distance metric
)
# Add documents (Chroma handles embedding)
collection.add(
documents=[
"The quick brown fox jumps over the lazy dog.",
"Machine learning is a subset of artificial intelligence.",
"Python is a versatile programming language.",
],
metadatas=[
{"source": "sample.txt", "category": "text"},
{"source": "ml_intro.txt", "category": "ai"},
{"source": "python_intro.txt", "category": "programming"},
],
ids=["doc1", "doc2", "doc3"]
)
# Query
results = collection.query(
query_texts=["What is AI?"],
n_results=2,
where={"category": "ai"} # Metadata filtering
)
for doc, meta, distance in zip(
results["documents"][0],
results["metadatas"][0],
results["distances"][0]
):
print(f"Distance: {distance:.3f} | Source: {meta['source']}")
print(f"Content: {doc[:100]}\n")
# Update and delete
collection.update(ids=["doc1"], documents=["Updated text content"])
collection.delete(ids=["doc1"])
print(f"Collection count: {collection.count()}")Pinecone: Managed Production
Pinecone trades cost for zero operations โ no servers to size, patch, or scale, just an index and an API key.
# pip install pinecone-client
from pinecone import Pinecone, ServerlessSpec
import numpy as np
pc = Pinecone(api_key="your-pinecone-api-key")
# Create index
if "my-index" not in [idx.name for idx in pc.list_indexes()]:
pc.create_index(
name="my-index",
dimension=1536, # Must match your embedding model
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
index = pc.Index("my-index")
# Upsert vectors (with metadata)
from openai import OpenAI
client = OpenAI()
def embed(texts: list[str]) -> list[list[float]]:
response = client.embeddings.create(
model="text-embedding-3-small",
input=texts
)
return [item.embedding for item in response.data]
documents = [
{"id": "doc1", "text": "Introduction to machine learning concepts."},
{"id": "doc2", "text": "Python data structures and algorithms."},
{"id": "doc3", "text": "Deep learning with PyTorch tutorial."},
]
texts = [d["text"] for d in documents]
embeddings = embed(texts)
# Batch upsert
vectors = [
{
"id": doc["id"],
"values": emb,
"metadata": {"text": doc["text"], "category": "tech"}
}
for doc, emb in zip(documents, embeddings)
]
index.upsert(vectors=vectors, namespace="production")
# Query
query_embedding = embed(["how does machine learning work?"])[0]
results = index.query(
namespace="production",
vector=query_embedding,
top_k=3,
include_values=False,
include_metadata=True,
filter={"category": {"$eq": "tech"}} # Metadata filter
)
for match in results.matches:
print(f"Score: {match.score:.3f} | ID: {match.id}")
print(f"Text: {match.metadata['text']}\n")
# Index statistics
stats = index.describe_index_stats()
print(f"Total vectors: {stats.total_vector_count}")pgvector: PostgreSQL Integration
pgvector adds vector similarity search directly to PostgreSQL, so a team already running Postgres doesn't need a second database just for embeddings.
# pip install psycopg2-binary pgvector
import psycopg2
from pgvector.psycopg2 import register_vector
import numpy as np
# Connect to PostgreSQL with pgvector
conn = psycopg2.connect("postgresql://user:password@localhost/mydb")
register_vector(conn)
cur = conn.cursor()
# Enable extension and create table
cur.execute("CREATE EXTENSION IF NOT EXISTS vector")
cur.execute("""
CREATE TABLE IF NOT EXISTS documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
category VARCHAR(50),
embedding vector(1536) -- Match your model's dimensions
)
""")
# Create HNSW index for fast approximate search
cur.execute("""
CREATE INDEX IF NOT EXISTS documents_embedding_idx
ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64)
""")
conn.commit()
# Insert with embeddings
def insert_document(content: str, category: str, embedding: list[float]):
cur.execute(
"INSERT INTO documents (content, category, embedding) VALUES (%s, %s, %s)",
(content, category, np.array(embedding))
)
conn.commit()
# Similarity search
def search(query_embedding: list[float], top_k: int = 5, category: str | None = None):
if category:
cur.execute("""
SELECT content, category, 1 - (embedding <=> %s) AS similarity
FROM documents
WHERE category = %s
ORDER BY embedding <=> %s
LIMIT %s
""", (np.array(query_embedding), category, np.array(query_embedding), top_k))
else:
cur.execute("""
SELECT content, category, 1 - (embedding <=> %s) AS similarity
FROM documents
ORDER BY embedding <=> %s
LIMIT %s
""", (np.array(query_embedding), np.array(query_embedding), top_k))
return cur.fetchall()
# Hybrid search (semantic + keyword)
def hybrid_search(query: str, query_embedding: list[float], top_k: int = 5):
cur.execute("""
SELECT content, category,
ts_rank(to_tsvector(content), plainto_tsquery(%s)) AS keyword_score,
1 - (embedding <=> %s) AS semantic_score,
-- Combine: 50% keyword + 50% semantic
(ts_rank(to_tsvector(content), plainto_tsquery(%s)) * 0.5 +
(1 - (embedding <=> %s)) * 0.5) AS combined_score
FROM documents
WHERE to_tsvector(content) @@ plainto_tsquery(%s)
OR (1 - (embedding <=> %s)) > 0.7
ORDER BY combined_score DESC
LIMIT %s
""", (query, np.array(query_embedding), query, np.array(query_embedding),
query, np.array(query_embedding), top_k))
return cur.fetchall()Qdrant: High-Performance Self-Hosted
Qdrant is a Rust-based, self-hosted vector database that pairs strong performance with a straightforward setup โ the best price-to-performance ratio among self-hosted options.
# pip install qdrant-client
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, PointStruct,
Filter, FieldCondition, MatchValue, SearchRequest
)
# Connect to local Qdrant (docker run -p 6333:6333 qdrant/qdrant)
client = QdrantClient(host="localhost", port=6333)
# Or cloud
# client = QdrantClient(url="https://your-cluster.qdrant.io", api_key="your-key")
# Create collection
client.recreate_collection(
collection_name="articles",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
# Upsert points
points = [
PointStruct(
id=1,
vector=[0.1] * 1536, # Your actual embedding
payload={"text": "Article about ML", "category": "ai", "views": 1500}
),
PointStruct(
id=2,
vector=[0.2] * 1536,
payload={"text": "Python tutorial", "category": "programming", "views": 3000}
),
]
client.upsert(collection_name="articles", points=points)
# Search with filters
results = client.search(
collection_name="articles",
query_vector=[0.1] * 1536,
limit=5,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="ai")),
FieldCondition(key="views", range={"gte": 1000})
]
),
with_payload=True
)
for r in results:
print(f"Score: {r.score:.3f} | Text: {r.payload['text']}")Choosing the Right Database
The right database is a function of your stage, existing infrastructure, and scale โ not a single "best" answer.
- Prototyping โ use Chroma; zero setup, Python-native, nothing to provision.
- Already running PostgreSQL โ use pgvector; no new infrastructure to operate.
- Zero-ops managed cloud โ use Pinecone or Weaviate Cloud.
- Maximum performance, self-hosted โ use Qdrant; the best performance-to-cost ratio in this category.
- Multimodal vectors (images + text) โ use Weaviate; native multimodal support.
- Already on Elasticsearch โ stay there and use its built-in kNN rather than adding a new system.
Scale thresholds: under 100K vectors, any option works โ choose by ops preference. 100Kโ10M, Qdrant, Pinecone, and Weaviate all scale fine. 10M+, Pinecone or Qdrant with proper instance sizing. 1B+, Pinecone, Milvus, or Elasticsearch.
The Bottom Line
Vector databases have matured fast enough that most applications are well served by Chroma in development and Qdrant or pgvector in production โ at a fraction of managed-service cost.
Pinecone wins on operational simplicity: no servers, no maintenance, automatic scaling. If your team's time is worth more than the $70+/month gap versus self-hosting, that simplicity is usually worth paying for.
For the retrieval application layer that uses these databases, see our RAG system tutorial. For understanding the embeddings stored in these databases, see our embeddings explained guide.
Further Reading
- LangChain Tutorial 2025: Build AI Applications with Chains and Agents
- Streamlit Tutorial: Build and Deploy AI Apps with Python in Minutes
- CrewAI Tutorial: Build Multi-Agent AI Systems That Work Together
- OpenAI API Integration: Complete Python Guide for Building AI Applications
- Semantic Search Tutorial: Build Search That Understands Meaning, Not Just Keywords
- Build a Research Agent: End-to-End Autonomous Research Tool in Python
- Python for Machine Learning 2026 โ Your First ML Project with scikit-learn
- Multimodal AI Explained: How Models Process Text, Images, Audio, and Video
Advertisement
๐ฌ DiscussionPowered by GitHub Discussions
Frequently Asked Questions

Software Testing Expert & Prompt Engineering
Ensures every release is bug-free through rigorous testing, and crafts high-precision prompts that power our AI-driven workflows. Abdullah Al Arman Emon leads QA and prompt engineering across AiTechWorlds.
Not sure yet? Ask AI about this article
Get an instant, unbiased AI summary of โVector Database Guide: Pinecone, Weaviate, Chroma, and pgvector Comparedโ.
Advertisement
Related Articles
AI API Cost Management: How to Cut LLM Costs by 80% Without Losing Quality
AI API cost management โ practical strategies to reduce OpenAI, Claude, and Gemini API costs by 80% using model selection, caching, RAG, prompt optimization, and batch processing.
Build an AI Chatbot with Python: Complete Guide from Scratch to Deployment
Build an AI chatbot with Python โ complete tutorial from OpenAI API integration to conversation memory, streaming responses, and deploying a production-ready chatbot application.
Build a Personal AI Assistant: Complete Python Project with Memory and Tools
Build a personal AI assistant in Python with persistent memory, web search, file access, and calendar integration โ a complete project from architecture to working prototype.
CrewAI Tutorial: Build Multi-Agent AI Systems That Work Together
CrewAI tutorial โ build multi-agent AI systems where specialized agents collaborate to complete complex tasks, with practical Python examples for research, coding, and content workflows.