Model or dataset
philippgille/chromem-go avatar
philippgille/chromem-go

chromem-go: An Embedded Vector Database for Go Apps That Cannot Run a Separate Service

Embeddable vector database for Go with Chroma-like interface and zero third-party dependencies. In-memory with optional persistence.

1,056 stars78 forksGoMPL-2.0

At a glance

What is it?
chromem-go puts an in-memory vector store inside your Go binary, with a Chroma-like API and no third-party dependencies. It is a good fit for small to medium collections and a poor fit when you need scale or a stable API surface.
Who is it for?
Adopt chromem-go when your Go service needs retrieval over a bounded document set and you would rather not operate a separate database process. Do not adopt it if you need millions of documents, a frozen API, or a full Chroma feature surface.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The Problem: RAG in Go Without a Second Process

Adding retrieval augmented generation to a Go service usually means standing up a vector database somewhere else. That is a second process to deploy, monitor, back up, and keep in sync with the application. The README frames the alternative directly: chromem-go is embeddable, so you add embeddings-based features to your Go app, in the project's words, without having to run a separate database, comparing the relationship to using SQLite instead of PostgreSQL or MySQL. The target reader is a Go developer who already has documents, already has or can obtain embeddings, and wants nearest neighbor search inside the same binary. The README lists RAG and question answering, text and code search, recommendation systems, classification, and clustering as the use cases. One clarification the project makes about itself is worth repeating because it is easy to get wrong: this is not a client library for Chroma and not a reimplementation of it. It is a database on its own, inspired by Chroma's interface.

The Chroma-Shaped API and the Go-Idiomatic Variants

The README shows Chroma's Python core API and then shows the Go equivalent side by side. You call chromem.NewDB() to get a database handle. The README explains the naming choice: it is called DB rather than client because there is no client-server separation, since the database is embedded. From there you call db.CreateCollection with a name and two additional arguments (the README's example passes nil, nil), and you get a collection. Collection.Add takes a context, a slice of unique IDs, an embeddings argument, a slice of metadata maps, and the documents themselves. In the README's example the embeddings argument is nil, which signals that chromem-go should generate them for you. Collection.Query takes a context, a query string, a result count, an optional metadata filter, and an optional document filter expressed as a map with a $contains key. There is also GetCollection, GetOrCreateCollection, and DeleteCollection. The project states that it started with only the four core methods and has added more since, and that it does not intend to cover 100 percent of Chroma's API surface. Some methods are deliberately more Go-idiomatic than the Chroma port. The README also notes an AddConcurrently method for multi-threaded insertion, which is the kind of addition the Chroma-shaped interface would not have suggested on its own.

Embedding Generation Is Built In, and That Is the Main Coupling

The step that usually requires glue code in a Go RAG setup is embedding generation, and chromem-go handles it. The README states that the database stores embeddings alongside documents, that you can provide those embeddings yourself, or that they can be created by embedding models. It says chromem-go can do this for you and supports multiple embedding providers and models out of the box, naming OpenAI's text-embedding-3-small as an example. That convenience has a cost that the README does not dwell on: if you let the library call an embedding provider, your query path now depends on a network call to that provider, and your document ingestion does too. The zero-third-party-dependency claim applies to the Go module graph, not to your runtime dependencies. A deployment that uses a hosted embedding model still needs outbound network access and an API key. If you want a fully self-contained binary with no external calls at query time, you would pass your own embeddings, which the API supports but which pushes the embedding work back onto you.

Getting It Running: Installation and the Core Calls

Installation is the standard Go module path: go get github.com/philippgille/chromem-go. The README's usage example imports the package as github.com/philippgille/chromem-go and calls chromem.NewDB() for an in-memory database, which the README describes as suitable for easy prototyping and notes that persistence can be added easily. Collection creation is db.CreateCollection("all-my-documents", nil, nil). Insertion in the README example is collection.Add(ctx, []string{"doc1", "doc2"}, nil, []map[string]string{{"source": "notion"}, {"source": "google-docs"}}, []string{"This is document1", "This is document2"}), where the nil in the third position tells the library to handle embedding automatically. Querying is collection.Query(ctx, "This is a query document", 2, map[string]string{"metadata_field": "is_equal_to_this"}, map[string]string{"$contains": "search_string"}). The first filter map matches metadata values, and the second filters on document content using the $contains operator. The README points to the examples directory for a fuller RAG walkthrough and to the Godoc page for the complete interface. Note that the README marks update and delete as future work, so a collection is append-oriented in the documented API.

Benchmarks and the Scale Boundary

The project publishes query timings rather than a feature comparison. The README states that on a mid-range 2020 Intel laptop CPU you can query 1,000 documents in 0.3 ms and 100,000 documents in 40 ms, with what it describes as very few and small memory allocations. These are the project's own numbers and the hardware is described only loosely, so treat them as an order-of-magnitude signal rather than a specification. The more useful sentence is the one about scope: the focus is not scale in the millions of documents or number of features, but simplicity and performance for the most common use cases. That is a direct statement that this is not the tool for a corpus in the millions. The reason is structural. An in-memory store with optional persistence keeps the working set resident, and nearest neighbor search over that set runs in the process. Once the collection outgrows comfortable memory, the design that made it convenient is the design that hurts. If your retrieval corpus is a company wiki, a product manual set, or a few hundred thousand chunks, the stated numbers suggest you are inside the intended range. If it is a web-scale index, you are not.

Beta Status, Breaking Changes, and the Maintenance Question

The README carries a warning: the project is in beta, under heavy construction, and may introduce breaking changes in releases before v1.0.0, with all changes documented in the CHANGELOG. That is the single most important operational fact here. Pinning a version is not optional caution, it is the expected workflow, because the API you compile against today may change on the next release. The release cadence visible in the material is modest: v0.5.0 in March 2024, v0.6.0 in April 2024, v0.7.0 in September 2024, with no v1.0.0 in the list. The repository is not archived and was still receiving pushes as of September 2026, so the project is alive, but the versioning tells you the author has not declared the interface stable. Your upgrade cost is therefore the cost of reading the CHANGELOG and adjusting call sites on each bump, plus re-embedding if a change touches how embeddings are stored or compared. The licence is MPL-2.0, a file-level copyleft licence. The practical implication for most teams is that modifications to chromem-go's own source files carry obligations, while your application code that merely imports the library generally does not. That is a general description, not legal advice, and anyone embedding the library in a distributed product should read the licence text and consult counsel rather than rely on a summary.

When chromem-go Is the Wrong Choice

The clearest case against chromem-go is a corpus that does not fit in memory. The README's own framing excludes millions of documents, and no amount of tuning changes the fact that the index lives in the process. A second case is a team that needs the full Chroma feature surface or wire compatibility with an existing Chroma deployment, since the project explicitly does not aim to cover 100 percent of Chroma's API and is not a Chroma client. A third case is a service that must not call an external embedding API at query time but also cannot run its own embedding model; the library's automatic embedding is convenient precisely because it calls out. A fourth case is an application that needs update and delete on documents today, because the README lists those as planned rather than present. Finally, a team that cannot absorb breaking changes between minor versions should wait for v1.0.0 or pin hard and budget for migration work. None of these are defects in the library. They are the boundary of what an embedded, in-memory store with a pre-1.0 interface is for.

The Alternative: Running Chroma as a Separate Service

The obvious alternative is Chroma itself, deployed as a service. The difference is architectural, not cosmetic. With Chroma you run a server process and your Go code talks to it over the network, which means you get the full feature set the project maintains, independent scaling of the vector store from your application, and a data lifecycle that survives application restarts without relying on the library's persistence option. You also inherit a deployment target, a network hop on every query, connection handling, and the operational work of keeping that process healthy. chromem-go inverts each of those: no separate process, no network hop for the search itself, but a store bounded by your process memory and a smaller feature set. The README's SQLite versus PostgreSQL comparison is the right frame. Choose the embedded option when the dataset is modest and the operational simplicity is worth more than the ceiling. Choose the service when you need the ceiling, the features, or shared access from more than one process. If you are in Go and want embeddings without a service, chromem-go is the direct answer; if you need a vector store that other languages and other services also query, an embedded Go library is the wrong shape entirely.

Editorial conclusion

Adopt chromem-go when your Go service needs retrieval over a bounded document set and you would rather not operate a separate database process. Do not adopt it if you need millions of documents, a frozen API, or a full Chroma feature surface. Before committing, check the CHANGELOG for breaking changes since v0.7.0, confirm your embedding provider is among the supported ones, and decide whether the default in-memory storage plus the optional persistence path meets your durability requirement.

Official sources

  1. Issues
  2. License: MPL-2.0
  3. philippgille/chromem-go on GitHub
  4. README
  5. Releases
Community notes

Community notes