Skip to content
HUIAHUB

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.

Edited by Published 7 min read19 sources

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

pgvectorQdrantChromaMilvus
LicencePostgreSQL LicenseApache 2.0Apache 2.0Apache 2.0
Runs asPostgres extensionServer (Docker/binary); in-process EdgeIn-process library or serverLite library, Standalone Docker, Distributed on Kubernetes
Local dev without a serverNeeds PostgresPython client local modeYes, in-memory or persistentMilvus Lite (Linux, macOS)
Managed optionMany hosted Postgres providersQdrant Cloud (free tier)Chroma CloudZilliz Cloud
ANN indexesHNSW, IVFFlatHNSW (filter-aware)HNSW single-node, SPANN distributedFLAT, IVF family, HNSW family, DISKANN, SCANN, GPU
FilteringSQL WHERE, iterative scansPayload filters inside graph searchwhere and where_documentBoolean expressions, scalar indexes
Horizontal scaleReplicas, Citus or other shardingSharding and replicationDistributed Chroma, Chroma CloudDistributed 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 situationStart withWhy, per the docs
Notebook prototype, one developerChroma (persistent client) or Milvus LiteBoth run in-process with a pip install and no server
Production app already on Postgres, vectors tied to relational rowspgvectorJoins, transactions and backups you already run; HNSW or IVFFlat when exact search gets slow
Many metadata filters per query, or strict filtersQdrantPayload indexes add filter-aware edges to the HNSW graph
Multi-tenant SaaSQdrant (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 machineMilvus StandaloneA single Docker image; Milvus gives 100 million as its Standalone ceiling
100 million to billions of vectorsMilvus DistributedSeparate ingestion and query nodes; Milvus's stated range for this mode
Need GPU index buildsMilvus or QdrantMilvus lists GPU_CAGRA and other GPU indexes; Qdrant lists NVIDIA and AMD GPU support for indexing
Want no database to operateAny managed option aboveEach 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. 1.GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres · GitHubRepositoryPrimarygithub.com
  2. 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. 3.GitHub - chroma-core/chroma: Search infrastructure for AI · GitHubRepositoryPrimarygithub.com
  4. 4.GitHub - milvus-io/milvus: Milvus is a high-performance, cloud-native vector database built for scalable vector ANN search · GitHubRepositoryPrimarygithub.com
  5. 5.github.com/pgvector/pgvector/blob/master/LICENSERepositoryPrimary
  6. 6.github.com/qdrant/qdrant-clientRepositoryPrimary
  7. 7.qdrant.tech/documentation/concepts/indexingWeb
  8. 8.qdrant.tech/documentation/concepts/collectionsWeb
  9. 9.qdrant.tech/documentation/concepts/filteringWeb
  10. 10.docs.trychroma.com/docs/run-chroma/clientsOfficial docsPrimary
  11. 11.docs.trychroma.com/docs/collections/configureOfficial docsPrimary
  12. 12.docs.trychroma.com/docs/querying-collections/metadata-filteringOfficial docsPrimary
  13. 13.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/getstarted/install-overview.mdWeb
  14. 14.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/getstarted/milvus_lite.mdWeb
  15. 15.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/indexes/index-explained.mdWeb
  16. 16.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/reference/scalar_index.mdWeb
  17. 17.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/indexes/scalar/bitmap.mdWeb
  18. 18.raw.githubusercontent.com/milvus-io/milvus-docs/v3.0.x/site/en/userGuide/search-query-get/metric.mdWeb
  19. 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