ComparisonRAG, search & data
pgvector, Qdrant, Chroma or Milvus: how to choose a vector database
Choose a vector database for RAG or search by comparing pgvector, Qdrant, Chroma and Milvus on deployment, filtering, index types and licence.
To choose a vector database, start from where your data and team already are. If you run Postgres, pgvector adds vector search to it. Qdrant suits payload-heavy filtering, Chroma suits local prototypes and small apps, and Milvus is built for very large collections spread across a cluster.
All four are open source under permissive licences, and each has a hosted option. The differences that matter are how you deploy them, how they filter, and which indexes they offer. Everything below comes from each project's README and official documentation.
What does a vector database do that a plain table does not?
An embedding model turns text, images or audio into a list of numbers. Similar inputs end up close together in that space. A vector database stores those lists and answers one question quickly: which stored vectors are nearest to this query vector?
A plain table can hold the numbers, but finding the nearest ones means comparing the query against every row. Vector databases add approximate nearest-neighbor (ANN) indexes such as HNSW or IVF. Those indexes skip most rows and accept a small loss in recall for a large gain in speed.
The other half of the job is filtering. Real queries look like "nearest chunks for tenant 42, published after March". How each system combines a filter with an ANN search is one of the biggest practical differences between them.
pgvector: vectors inside Postgres
pgvector (opens in a new tab) is a Postgres extension. It adds vector, halfvec, bit and sparsevec column types, distance operators, and two ANN index types: HNSW and IVFFlat. Without an index it runs exact search with perfect recall.
CREATE EXTENSION vector;
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(1536));
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);
SELECT * FROM items ORDER BY embedding <=> '[...]' LIMIT 5;
pgvector runs wherever your Postgres runs. The README lists packages for APT, Yum, Homebrew, Docker and others, and says many hosted Postgres providers ship it preinstalled. Vectors get Postgres transactions, joins, backups and WAL-based replication.
In pgvector, a filter is a normal WHERE clause. With an approximate index, pgvector applies the filter after scanning the index, so a selective filter can return fewer rows than your LIMIT. Version 0.8.0 added iterative index scans that keep reading the index until enough rows match. Partial indexes and list partitioning are the other options the docs suggest.
pgvector's HNSW and IVFFlat indexes accept vector columns up to 2,000 dimensions and halfvec up to 4,000. A non-partitioned Postgres table tops out at 32 TB by default. For horizontal scale the README points to replicas and sharding tools such as Citus.
Qdrant: filtering and payloads
Qdrant (opens in a new tab) is a standalone vector search engine written in Rust. Each record is a point: one or more vectors plus a JSON payload. Its README describes it as built for extended filtering support.
docker run -p 6333:6333 qdrant/qdrant
That command starts a server without authentication, open on all interfaces, as the README warns. Read Qdrant's security guide before exposing it.
Qdrant runs as a server (Docker or binary) with REST and gRPC APIs. The Python client's local mode, QdrantClient(":memory:") or QdrantClient(path=...), runs the same API without a server for tests and notebooks. Qdrant Edge runs inside the application process. Qdrant Cloud is the managed service and has a free tier.
Qdrant payload filters combine must, should and must_not clauses with conditions such as exact match, match any, numeric and datetime ranges, geo radius and polygons, full-text match and nested objects. Payload indexes come in keyword, integer, float, bool, geo, datetime, text and UUID types.
Qdrant's indexing docs explain the main design choice. Plain HNSW degrades under strict filters, so Qdrant adds extra graph edges based on indexed payload values. Filtering then happens during graph traversal. The docs advise creating payload indexes right after creating a collection, before loading data, so those edges get built.
HNSW is Qdrant's only dense vector index (defaults: m 16, ef_construct 100). It supports Dot, Cosine, Euclid and Manhattan distance, named vectors (several per point, each with its own size and distance), sparse vectors and multivectors for late-interaction models such as ColBERT. Built-in quantization reduces memory use. Sharding and replication handle horizontal scale.
Chroma: embedded and local-first
Chroma (opens in a new tab) starts with one install and a few lines of Python:
pip install chromadb
import chromadb
client = chromadb.PersistentClient(path="./chroma")
collection = client.get_or_create_collection("docs")
collection.add(
ids=["doc1", "doc2"],
documents=["First document", "Second document"],
metadatas=[{"source": "notion"}, {"source": "wiki"}],
)
results = collection.query(
query_texts=["a question"],
n_results=2,
where={"source": "notion"},
)
Chroma's Python client can run in memory, persist to a local directory, or connect to a server started with chroma run --path <dir>. TypeScript and Rust clients need that server. Chroma Cloud is the hosted service. The README notes that Chroma can handle tokenization and embedding for you, or accept your own embeddings.
In Chroma, the where argument filters on metadata with $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $and, $or, plus $contains and $not_contains for arrays. where_document filters on the document text with $contains or $regex.
Single-node Chroma uses HNSW. Distributed Chroma and Chroma Cloud use SPANN. Distance is set per collection to l2 (the default, squared L2), cosine or ip. HNSW defaults are ef_construction 100, ef_search 100 and max_neighbors 16.
Milvus: large collections
Milvus (opens in a new tab) is written in Go and C++ and designed for horizontal scale. It is an LF AI & Data Foundation project, with Zilliz as its major contributor.
pip install -U "pymilvus[milvus-lite]"
from pymilvus import MilvusClient
client = MilvusClient("milvus_demo.db") # Milvus Lite, local file
client.create_collection(collection_name="docs", dimension=768)
Milvus has three modes, and its installation docs give a size for each:
- Milvus Lite, a Python library, for prototypes and datasets up to a few million vectors. It runs on Ubuntu 20.04+ and macOS 11+, uses only the FLAT index whatever you specify, and has no partitions.
- Milvus Standalone, a single Docker image, for medium datasets up to 100 million vectors.
- Milvus Distributed, on Kubernetes, for 100 million up to tens of billions of vectors, with ingestion and queries handled by separate nodes.
Zilliz Cloud is the managed version, offered as Serverless, Dedicated or bring-your-own-cloud.
Milvus searches take boolean filter expressions over scalar fields, for example color in ["red", "green", "blue"]. Operators include comparisons, in, like, and JSON and array functions such as JSON_CONTAINS and ARRAY_CONTAINS. Scalar indexes such as INVERTED and BITMAP speed these up. Multi-tenancy can be isolated at the database, collection, partition or partition-key level.
Milvus has the widest index choice of the four: FLAT, the IVF family (IVF_FLAT, IVF_SQ8, IVF_PQ, IVF_RABITQ), HNSW and its quantized variants, DISKANN, SCANN, and GPU indexes such as GPU_CAGRA. Float vectors use L2, IP or COSINE. It also supports BM25 full-text search and sparse vectors alongside dense ones in the same collection.
Licences and hosting options
| pgvector | Qdrant | Chroma | Milvus | |
|---|---|---|---|---|
| Licence | PostgreSQL License | Apache 2.0 | Apache 2.0 | Apache 2.0 |
| Runs as | Postgres extension | Server (Docker/binary); in-process Edge | In-process library or server | Lite library, Standalone Docker, Distributed on Kubernetes |
| Local dev without a server | Needs Postgres | Python client local mode | Yes, in-memory or persistent | Milvus Lite (Linux, macOS) |
| Managed option | Many hosted Postgres providers | Qdrant Cloud (free tier) | Chroma Cloud | Zilliz Cloud |
| ANN indexes | HNSW, IVFFlat | HNSW (filter-aware) | HNSW single-node, SPANN distributed | FLAT, IVF family, HNSW family, DISKANN, SCANN, GPU |
| Filtering | SQL WHERE, iterative scans | Payload filters inside graph search | where and where_document | Boolean expressions, scalar indexes |
| Horizontal scale | Replicas, Citus or other sharding | Sharding and replication | Distributed Chroma, Chroma Cloud | Distributed mode |
Prices for the hosted services change and are not listed here. Check each provider's pricing page before committing.
A decision table for choosing a vector database by project size
Use this as a starting point, then test with your own data. The size bands for Milvus come from Milvus's own installation guidance. The other rows follow from each project's documented deployment model.
| Your situation | Start with | Why, per the docs |
|---|---|---|
| Notebook prototype, one developer | Chroma (persistent client) or Milvus Lite | Both run in-process with a pip install and no server |
| Production app already on Postgres, vectors tied to relational rows | pgvector | Joins, transactions and backups you already run; HNSW or IVFFlat when exact search gets slow |
| Many metadata filters per query, or strict filters | Qdrant | Payload indexes add filter-aware edges to the HNSW graph |
| Multi-tenant SaaS | Qdrant (payload partitioning) or Milvus (partition key) | Both document tenant isolation inside one collection; pgvector suggests list partitioning |
| Up to about 100 million vectors on one machine | Milvus Standalone | A single Docker image; Milvus gives 100 million as its Standalone ceiling |
| 100 million to billions of vectors | Milvus Distributed | Separate ingestion and query nodes; Milvus's stated range for this mode |
| Need GPU index builds | Milvus or Qdrant | Milvus lists GPU_CAGRA and other GPU indexes; Qdrant lists NVIDIA and AMD GPU support for indexing |
| Want no database to operate | Any managed option above | Each project has a hosted service |
Moving later is mostly an export and re-import job, since all four accept vectors you compute yourself.
Frequently asked questions
Can I use the same embeddings if I switch from one vector database to another?
Yes, as long as you keep the same embedding model and distance function. The vectors are plain arrays of floats, so you export them with their IDs and metadata and load them into the new store. Indexes are rebuilt on the new side, and filter syntax has to be rewritten because each project uses its own.
Which distance metric should I pick?
Use the one your embedding model was trained for, usually stated on its model card or API docs. All four projects support cosine, inner product and L2 for dense vectors. Chroma defaults to squared L2, so set `cosine` explicitly if your model expects it.
Is Chroma suitable for production?
Chroma runs as a server with `chroma run` and has a distributed mode and a hosted Chroma Cloud that use a SPANN index. Chroma's docs describe the in-memory client as a fit for experiments that do not need persistence.
Do I need a separate vector database for hybrid keyword and vector search?
Not necessarily. pgvector's docs show combining it with Postgres full-text search, Qdrant supports sparse vectors and fusion methods such as Reciprocal Rank Fusion, and Milvus has built-in BM25 full-text search. Chroma's README lists hybrid and full-text search for Chroma Cloud.
Sources
- 1.GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres · GitHubRepositoryPrimarygithub.com
- 2.GitHub - qdrant/qdrant: Qdrant - High-performance, massive-scale Vector Database and Vector Search Engine for the next generation of AI. Also available in the cloud https://cloud.qdrant.io/ · GitHubRepositoryPrimarygithub.com
- 3.GitHub - chroma-core/chroma: Search infrastructure for AI · GitHubRepositoryPrimarygithub.com
- 4.GitHub - milvus-io/milvus: Milvus is a high-performance, cloud-native vector database built for scalable vector ANN search · GitHubRepositoryPrimarygithub.com
- 5.github.com/pgvector/pgvector/blob/master/LICENSERepositoryPrimary
- 6.github.com/qdrant/qdrant-clientRepositoryPrimary
- 7.qdrant.tech/documentation/concepts/indexingWeb
- 8.qdrant.tech/documentation/concepts/collectionsWeb
- 9.qdrant.tech/documentation/concepts/filteringWeb
- 10.docs.trychroma.com/docs/run-chroma/clientsOfficial docsPrimary
- 11.docs.trychroma.com/docs/collections/configureOfficial docsPrimary
- 12.docs.trychroma.com/docs/querying-collections/metadata-filteringOfficial docsPrimary
- 13.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/getstarted/install-overview.mdWeb
- 14.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/getstarted/milvus_lite.mdWeb
- 15.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/indexes/index-explained.mdWeb
- 16.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/reference/scalar_index.mdWeb
- 17.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/indexes/scalar/bitmap.mdWeb
- 18.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/search-query-get/metric.mdWeb
- 19.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/search-query-get/boolean/boolean.mdWeb
Spotted an error? See our corrections policy.
Enjoyed this? Get the weekly brief.
New guides, Project & Tool of the Week and the AI developments that matter. One email, no spam.
Read next
- GuideRAG, search & data
Best embedding model for RAG: how to choose by size, dimensions, languages and cost
Pick the best embedding model for RAG by language, context length, vector size, hosting and price, then test it on your own documents first.
6 min read
- TutorialRAG, search & data
Build a RAG pipeline with Postgres and pgvector, step by step
Set up RAG with pgvector in your existing Postgres: a chunks table, an HNSW or IVFFlat index, the right distance operator and a filtered retrieval query.
6 min read
- Weekly digest
The week on HuiaHub: sandboxed agents, RAG tooling and local models
41 new HuiaHub pages this week: sandboxing coding agents, RAG retrieval, local models on Macs and phones, Claude Haiku 5.5 and six how-to guides.
4 min read