ChromaDB vs Pinecone vs pgvector: Which Vector Database Should You Use?

You have decided you need a vector database. Now the internet is throwing five different options at you. ChromaDB, Pinecone, pgvector, Weaviate, Qdrant — each with its own benchmarks, blog posts, and advocates.
The good news: for the majority of projects, the choice comes down to three options. This post gives you a practical, side-by-side comparison of ChromaDB, Pinecone, and pgvector — the three most commonly used vector stores in 2026 — so you can make the right call quickly and move on to building.
If you are not sure what any of these are, read What is a Vector Database? first.
The Three Contenders at a Glance
ChromaDB is an open-source vector database that runs in-process alongside your Python application. No server, no account, no infrastructure. You install a package and you have a vector database.
Pinecone is a fully managed cloud vector database. You create an account, create an index via API or dashboard, insert vectors, and query. Zero infrastructure to manage — Pinecone handles everything.
pgvector is a PostgreSQL extension. It adds a vector column type and ANN index to your existing Postgres database. If your application already uses Postgres, you get vector search without adding a new database to your stack.
Setup Complexity
ChromaDB
1pip install chromadb sentence-transformers1import chromadb
2from chromadb.utils import embedding_functions
3
4client = chromadb.PersistentClient(path="./chroma_data")
5ef = embedding_functions.SentenceTransformerEmbeddingFunction("all-MiniLM-L6-v2")
6collection = client.get_or_create_collection("docs", embedding_function=ef)
7
8collection.add(ids=["1"], documents=["Hello world"])
9results = collection.query(query_texts=["hi there"], n_results=1)
10print(results["documents"])Setup time: Under 5 minutes. Zero accounts, zero config files, zero external services.
Pinecone
1pip install pinecone1from pinecone import Pinecone, ServerlessSpec
2
3pc = Pinecone(api_key="your-pinecone-api-key")
4
5# Create an index (one-time setup)
6pc.create_index(
7 name="my-index",
8 dimension=384, # must match your embedding model's output dimension
9 metric="cosine",
10 spec=ServerlessSpec(cloud="aws", region="us-east-1")
11)
12
13index = pc.Index("my-index")
14
15# Upsert vectors (you must compute embeddings yourself)
16index.upsert(vectors=[
17 {"id": "doc_1", "values": [0.1, 0.2, ...384_floats...], "metadata": {"text": "Hello world"}}
18])
19
20# Query
21index.query(vector=[0.1, 0.05, ...384_floats...], top_k=3, include_metadata=True)Setup time: 10–20 minutes (account creation, API key, index creation). You must compute embeddings yourself before inserting — Pinecone stores and searches vectors, but does not embed text for you.
pgvector
1-- One-time: install extension
2CREATE EXTENSION IF NOT EXISTS vector;
3
4-- Create a table with a vector column
5CREATE TABLE documents (
6 id SERIAL PRIMARY KEY,
7 content TEXT,
8 category VARCHAR(50),
9 embedding vector(384) -- dimension must match your model
10);
11
12-- Create an HNSW index for fast ANN search
13CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops);1import psycopg2
2import numpy as np
3from sentence_transformers import SentenceTransformer
4
5model = SentenceTransformer("all-MiniLM-L6-v2")
6conn = psycopg2.connect("postgresql://user:password@localhost/mydb")
7cur = conn.cursor()
8
9# Insert a document
10text = "Device fails to boot after a firmware update"
11embedding = model.encode(text).tolist()
12cur.execute(
13 "INSERT INTO documents (content, category, embedding) VALUES (%s, %s, %s)",
14 (text, "hardware", embedding)
15)
16conn.commit()
17
18# Semantic search (cosine similarity)
19query_embedding = model.encode("laptop won't start after update").tolist()
20cur.execute(
21 """
22 SELECT content, category, 1 - (embedding <=> %s::vector) AS similarity
23 FROM documents
24 ORDER BY embedding <=> %s::vector
25 LIMIT 3
26 """,
27 (query_embedding, query_embedding)
28)
29for row in cur.fetchall():
30 print(f"[{row[2]:.3f}] [{row[1]}] {row[0]}")Setup time: 15–30 minutes (requires a running Postgres instance with pgvector installed). On managed Postgres (Supabase, Neon, AWS RDS, Railway), pgvector is usually one-click enabled.
pgvector Operators
pgvector adds three distance operators to SQL: <-> for L2 (Euclidean) distance, <#> for negative inner product, and <=> for cosine distance. To get similarity (0–1) from cosine distance, use 1 - (embedding <=> query_vector::vector).
Feature Comparison
| Feature | ChromaDB | Pinecone | pgvector |
|---|---|---|---|
| Hosting | Self-hosted / local | Fully managed cloud | Self-hosted or managed Postgres |
| Setup | pip install, 0 config | Account + API key | Postgres + extension |
| Handles embeddings | Yes (built-in) | No — you bring vectors | No — you bring vectors |
| Query language | Python API | Python/REST API | SQL |
| Metadata filtering | Yes (rich operators) | Yes | Yes (standard SQL WHERE) |
| Hybrid search | No (vector only) | Yes (sparse + dense) | Yes (with pg_trgm or FTS) |
| Max scale | ~1–5M vectors comfortably | Billions (managed) | 10–100M vectors (tuned) |
| Cost | Free (self-hosted) | Pay-per-use | Postgres hosting costs |
| ACID transactions | No | No | Yes (full Postgres) |
| Joins with other tables | No | No | Yes (SQL JOINs) |
| Backups / DR | Manual | Managed | Standard Postgres tooling |
Performance
Raw performance comparisons are heavily workload-dependent — dataset size, vector dimension, hardware, and query patterns all matter. Here is a practical summary of real-world behaviour:
ChromaDB is fast enough for collections under ~500,000 vectors on a single machine. Query latency at this scale is typically 5–50 ms depending on collection size and HNSW settings. It does not shard across machines, so a single server is your ceiling.
Pinecone is engineered for scale. It handles hundreds of millions of vectors with consistent low-latency queries (typically 10–100 ms server-side) because it distributes data across managed infrastructure. For datasets above 1 million vectors, Pinecone is difficult to match without significant self-hosted engineering.
pgvector with an HNSW index performs comparably to ChromaDB at small-to-medium scale. Performance degrades on very large collections without careful tuning (increasing m and ef_construction on the index, setting hnsw.ef_search at query time). The big advantage is that pgvector queries can JOIN with your existing tables in a single SQL statement — no round-trip between databases.
Cost
ChromaDB is free. You pay only for the infrastructure you run it on (a server or cloud VM). If you are already running an application server, you can run ChromaDB on the same machine at no additional cost.
Pinecone uses a pay-as-you-go model. The free tier supports one serverless index, limited to 2 GB of storage. Paid plans scale from around $0.033 per GB/month for storage, plus query costs. For a typical RAG application with 100,000 document chunks, the free tier is sufficient. For millions of vectors, costs can reach $100–500+/month depending on query volume. Always check the current pricing at pinecone.io.
pgvector has no licensing cost. You pay only for your Postgres instance. On Supabase's free tier, you get pgvector for free up to the storage limit. On a self-hosted Postgres server, pgvector is a single CREATE EXTENSION command — no additional cost.
When to Choose Each
Choose ChromaDB when:
- You are learning, prototyping, or building an internal tool
- Your dataset is under 500,000 vectors
- You want zero infrastructure overhead and a pure Python experience
- Budget is constrained and managed cloud services are not an option
- You want ChromaDB to handle embedding (no need to manage embedding models separately)
Choose Pinecone when:
- You are building a production application and want zero infrastructure to manage
- Your dataset exceeds 1 million vectors or will grow there
- You need hybrid search (combining dense vector search with keyword/BM25 search)
- Your team does not have the capacity to operate and tune a self-hosted vector database
- You need SLAs, managed backups, and enterprise support
Choose pgvector when:
- Your application already uses PostgreSQL
- You want to keep your stack simple — one database instead of two
- You need to JOIN vector search results with relational data in a single query
- You need ACID transactions across both vector and relational operations
- Your dataset is under 10 million vectors and you have a DBA who can tune Postgres
Head-to-Head: The Same RAG Pipeline in Each
To make the comparison concrete, here is the core retrieval step of a RAG pipeline implemented in each database.
ChromaDB:
1# Query — ChromaDB embeds the text automatically
2results = collection.query(
3 query_texts=["what is the cancellation policy?"],
4 n_results=3,
5 where={"category": "billing"}
6)
7chunks = results["documents"][0]Pinecone:
1from sentence_transformers import SentenceTransformer
2model = SentenceTransformer("all-MiniLM-L6-v2")
3
4# Must embed the query yourself
5query_vector = model.encode("what is the cancellation policy?").tolist()
6
7results = index.query(
8 vector=query_vector,
9 top_k=3,
10 filter={"category": "billing"},
11 include_metadata=True
12)
13chunks = [m["metadata"]["text"] for m in results["matches"]]pgvector:
1query_vector = model.encode("what is the cancellation policy?").tolist()
2
3cur.execute(
4 """
5 SELECT content
6 FROM documents
7 WHERE category = 'billing'
8 ORDER BY embedding <=> %s::vector
9 LIMIT 3
10 """,
11 (query_vector,)
12)
13chunks = [row[0] for row in cur.fetchall()]ChromaDB has the least boilerplate. pgvector gives you the full power of SQL. Pinecone is the most verbose but removes all infrastructure concerns.
What About Weaviate, Qdrant, and Milvus?
These are strong options, but serve different niches:
Qdrant — excellent choice if pgvector does not scale enough for you but you want to stay self-hosted. Written in Rust, it is faster than ChromaDB at large scale and has excellent filtering. Recommended over ChromaDB for collections above 500K vectors where you cannot use managed Postgres.
Weaviate — best for multi-modal use cases (text + images in the same index) and built-in hybrid search. More complex to operate than ChromaDB.
Milvus — designed for billion-scale enterprise deployments with a distributed architecture. Significantly more operational complexity. Only relevant if you are operating at Pinecone-scale with a requirement for on-premises hosting.
For most developers in 2026: ChromaDB → Pinecone or pgvector is the natural progression path. You do not need to evaluate Weaviate or Milvus unless you have specific requirements they uniquely address.
Quick Decision Flowchart
Do you already use PostgreSQL?
├── YES → Use pgvector. Keep your stack simple.
└── NO
├── Are you prototyping or building < 500K vectors?
│ └── YES → Use ChromaDB.
└── NO — production, > 1M vectors, or no ops capacity?
└── YES → Use Pinecone.
Key Takeaways
- ChromaDB: best for learning, prototyping, and small production apps. Zero setup. Free. Pure Python.
- Pinecone: best for production apps at scale where you want zero infrastructure overhead. Pay-as-you-go.
- pgvector: best when you are already on Postgres and want vector search without adding a new database. Full SQL power.
- There is no universally "best" choice — it depends on your dataset size, team capacity, budget, and existing stack.
- Start with ChromaDB. Migrate to pgvector or Pinecone when you outgrow it. The migration is straightforward because your embedding logic does not change.
What's Next in the Vector Database Series
- Next post: Build a Semantic Search Engine from Scratch with Python
- Advanced: Vector Database Optimisation for Production
This post is part of the Vector Database Series. Previous post: ChromaDB Tutorial: The Complete Beginner's Guide.
