Store and retrieve high-dimensional embeddings for semantic similarity search using vector indexing and approximate nearest-neighbour algorithms. Chroma simplifies building Retrieval-Augmented Generation (RAG) applications by handling embedding storage, HNSW indexing, and metadata filtering in a lightweight, deployable package.
Chroma is an open-source vector database built specifically to help developers store, search, and retrieve high-dimensional embeddings with as little friction as possible. It occupies a particular niche in the AI tooling ecosystem: it is the go-to starting point for teams building Retrieval-Augmented Generation (RAG) applications who want to move from zero to a working prototype in minutes rather than days. Understanding what Chroma is, what problem it solves, and where its boundaries lie will give you a clear map of the territory before diving into any individual feature.
Modern language model applications rarely rely on the model's parametric memory alone. Instead, they retrieve relevant context from an external knowledge base at query time and pass that context to the model. The retrieval step requires a very different kind of search from traditional keyword matching: you need semantic similarity search, where you find documents whose meaning is close to the query, not just documents that share the same words.
Semantic similarity is measured over embedding vectors — dense numerical representations of text (or images, audio, etc.) produced by an encoder model. A query is embedded into the same vector space as the stored documents, and the database returns the documents whose vectors are nearest to the query vector under some distance metric such as cosine similarity or L2 distance.
Building this infrastructure from scratch — managing embedding storage, indexing those vectors for fast approximate nearest-neighbour (ANN) search, filtering by metadata, and persisting everything to disk — is non-trivial. Chroma packages all of this into a single, lightweight library so you can focus on your application instead.
Chroma's architecture is organised around a small number of concepts that work together.
Figure 1: How the main Chroma components relate — your application talks to a Client, which manages Collections backed by an HNSW vector index, with an embedding function converting raw text into vectors.
A collection is the fundamental organisational unit in Chroma, analogous to a table in a relational database. Each collection holds a set of items, where each item consists of:
{"source": "arxiv", "year": 2024}).Rather than requiring you to embed documents separately before inserting them, Chroma accepts a pluggable embedding function at collection creation time. When you add raw text, Chroma calls this function internally to produce the vectors. The default uses the all-MiniLM-L6-v2 sentence-transformers model locally; you can swap in OpenAI embeddings, Cohere, HuggingFace, or any callable you define.
Under the hood, Chroma stores vectors in an HNSW (Hierarchical Navigable Small World) index via the hnswlib library. HNSW is a graph-based approximate nearest-neighbour algorithm that achieves sub-linear query time by navigating a multi-layer proximity graph. The trade-off versus exact search is a small, configurable recall loss in exchange for dramatically faster queries as the collection size grows.
One of Chroma's defining characteristics is that it offers three deployment modes with a largely consistent API:
| Mode | How it runs | Persistence | Typical use |
|---|---|---|---|
| In-process / ephemeral | Embedded in your Python process, data in memory | ❌ Lost on exit | Unit tests, quick experiments |
| In-process / persistent | Embedded, data written to a local directory | ✅ Survives restarts | Local development, single-machine apps |
| Client-server | Chroma runs as a separate HTTP server | ✅ | Multi-process access, staging environments |
The ability to start with zero infrastructure — just pip install chromadb and a few lines of Python — is the primary reason Chroma is the most common first vector database teams reach for.
Working with Chroma comes down to four operations on a collection:
add — Insert documents (and optionally pre-computed embeddings and metadata).query — Given one or more query texts or vectors, return the most similar items, optionally filtered by metadata.update / upsert — Modify existing items or insert them if they don't exist.delete — Remove items by ID or metadata filter.The query call is where Chroma does its core work: it embeds the query text, searches the HNSW index for the nearest vectors, applies any metadata filters, and returns ranked results with distances.
Chroma has first-class integrations with the two dominant LLM orchestration frameworks:
VectorStore implementation, meaning any LangChain retriever or RAG chain can swap Chroma in with one line of configuration.VectorStore in LlamaIndex's storage layer, compatible with its VectorStoreIndex and query engines.These integrations mean that prototype code written against Chroma can often be migrated to a different vector store later by changing a single constructor call.
Chroma is deliberately scoped. It excels at:
It is not designed for:
Understanding these boundaries early saves the common mistake of architecting a production system around Chroma only to hit scaling constraints later. Use it to learn the patterns and prove your retrieval logic; treat it as a prototype accelerator rather than a permanent foundation.