> ## Documentation Index
> Fetch the complete documentation index at: https://docs.topk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent: migrate from Chroma

> Step-by-step instructions for AI coding agents to move a user's Chroma collections to TopK with the CLI: inventory, export, import and verify.

You are an AI coding agent, and this page is for you. For an overview of TopK and the other agent pages, see [TopK for coding agents](https://docs.topk.io/agents.md). The human version of this guide is [Migrate from Chroma](https://docs.topk.io/migrate/from-chroma.md).

## Instructions

The user wants to move their Chroma collections to TopK. Follow the steps below in order. You run every command yourself; the user only logs in to TopK in the browser, gives you Chroma credentials if you can't find them, and approves the plan in step 4.

Rules:

* Never write to, modify or delete anything in Chroma. Every Chroma call in this guide is a read.
* Never print, log or commit the Chroma API key. Pass credentials to commands as environment variables on the same command line.
* Don't import anything into TopK until the user approves the plan in step 4.
* Use the `topk` CLI for TopK. Don't ask the user for a TopK API key: `topk login` is enough.
* Pass `--region <REGION>` to every data command (`topk import`, `topk sql`), and use the same region throughout. Account commands such as `topk login` and `topk project list` don't take it.
* If `TOPK_API_KEY` or `TOPK_PROJECT_ID` is set in the environment, run `topk` commands with them unset (`env -u TOPK_API_KEY -u TOPK_PROJECT_ID topk …`).
* Never run a command that waits for keyboard input: pass `--yes` to `topk import`.
* Chroma Cloud stops accepting writes on November 22, 2026 and stops serving reads on December 22, 2026. If today is after December 22, 2026 and the data is on Chroma Cloud, stop and tell the user the data can no longer be exported from Chroma Cloud.

### 1. Set up TopK

Follow steps 1 to 4 of the [Agent quickstart](https://docs.topk.io/agents/quickstart.md): install the CLI, log in, select a project and pick a region. Then come back here.

### 2. Find the Chroma credentials

Look for them in this order, and stop at the first that works:

1. Environment variables `CHROMA_TENANT`, `CHROMA_DATABASE` and `CHROMA_API_KEY`.
2. The user's project: search the code and `.env` files for `chromadb.CloudClient`, `CloudClient(` or `CHROMA_`. Note which collections the code uses.
3. Ask the user for their Chroma Cloud tenant ID, database name and API key. They're in the Chroma Cloud dashboard.

If the user runs self-hosted Chroma instead of Chroma Cloud, ask for its host and port, and use `chromadb.HttpClient(host=..., port=...)` everywhere this guide uses `chromadb.CloudClient(...)`.

### 3. Prepare a Python environment

Work in a new directory so the export files don't mix with the user's code:

```bash theme={null}
mkdir -p chroma-to-topk && cd chroma-to-topk
python3 -m venv .venv
.venv/bin/pip install --quiet chromadb
```

### 4. Inventory and plan

List every non-empty collection with its size, dimension, distance function and embedding function. Empty collections are left out, because the export skips them too:

```bash theme={null}
CHROMA_TENANT=... CHROMA_DATABASE=... CHROMA_API_KEY=... .venv/bin/python - <<'PY'
import os, chromadb
chroma = chromadb.CloudClient(
    tenant=os.environ["CHROMA_TENANT"],
    database=os.environ["CHROMA_DATABASE"],
    api_key=os.environ["CHROMA_API_KEY"],
)
for col in chroma.list_collections():
    count = col.count()
    if count == 0:
        continue
    config = col.configuration
    space = (config.get("spann") or config.get("hnsw") or {}).get("space", "l2")
    dim = len(col.get(limit=1, include=["embeddings"])["embeddings"][0])
    ef = config.get("embedding_function")
    ef = type(ef).__name__ if ef else "none"
    print(f"{col.name}\t{count} records\t{dim} dims\t{space}\t{ef}")
PY
```

Then check that each name is free in TopK. For each collection, run:

```bash theme={null}
topk sql --region <REGION> 'SELECT COUNT(*) FROM "<COLLECTION>"'
```

`Table does not exist` means the name is free. A count means a TopK collection with that name already exists. (`SHOW TABLES` isn't supported yet, so check each name.)

Show the user a plan as a table: each Chroma collection, its record count, dimension, distance function, the TopK collection it becomes (same name) and its TopK metric (`l2` → `euclidean`, `cosine` → `cosine`, `ip` → `dot_product`). Flag any name that already exists in TopK. If a collection's embedding function isn't `none` (for example `DefaultEmbeddingFunction`, or a hosted one whose name contains `ChromaCloud`), the user's application probably queries with `query_texts`, and Chroma embeds those queries for them. Tell the user, and recommend a semantic index on the document so TopK embeds both documents and queries; otherwise their code has to embed queries with the same model. Tell the user that the export pages through each collection, so records their application writes while it runs can be skipped or exported twice: they should pause writes to Chroma during the export, or run the export and import again just before switching writes to TopK. Ask the user to approve the plan and to say whether TopK should also embed the document text (a semantic index). Wait for their answer.

### 5. Export

Write the export script from step 1 of [Migrate from Chroma](https://docs.topk.io/migrate/from-chroma.md) to `chroma_to_topk.py`, unchanged. If the user approved only some collections, add a check at the top of the loop that skips the others. Run it:

```bash theme={null}
CHROMA_TENANT=... CHROMA_DATABASE=... CHROMA_API_KEY=... .venv/bin/python chroma_to_topk.py
```

It writes `<collection>.jsonl` and `<collection>.toml` for each collection, and prints one line per collection. If the user wants TopK to embed the text too, change `index = "keyword"` to `index = "semantic"` on the `document` line of each `.toml` file.

Read each `.toml` file and tell the user about two kinds of field the script changes, because their filters will need the new names or types:

* Fields starting with `meta_` were renamed: TopK field names can't start with `_`, and `id`, `document` and `embedding` are taken by the script.
* Fields declared `type = "text"` that hold numbers or booleans in Chroma had mixed types, so every value is now a string.

### 6. Import

Preview one spec first and check the plan it prints:

```bash theme={null}
topk import -f <COLLECTION>.toml --region <REGION> --dry-run
```

Then import every spec:

```bash theme={null}
for spec in *.toml; do
  topk import -f "$spec" --region <REGION> --yes
done
```

If an import stops partway, run the command the CLI prints after `to continue:`, adding `--yes`. It resumes the run from its last checkpoint.

### 7. Verify

For each collection, compare record counts. Chroma's count is in the step 4 output; TopK's is:

```bash theme={null}
topk sql --region <REGION> 'SELECT COUNT(*) FROM "<COLLECTION>"'
```

Then compare search results. This script takes 5 stored vectors from Chroma, runs each as a query against both systems and prints how many of the top 10 results they share. It sorts by the collection's metric, and runs `topk` without `TOPK_API_KEY` and `TOPK_PROJECT_ID`, so your login and selected project apply. Set `COLLECTION` and `REGION` first.

```bash theme={null}
COLLECTION=... REGION=... \
CHROMA_TENANT=... CHROMA_DATABASE=... CHROMA_API_KEY=... .venv/bin/python - <<'PY'
import json, os, subprocess, chromadb
chroma = chromadb.CloudClient(
    tenant=os.environ["CHROMA_TENANT"],
    database=os.environ["CHROMA_DATABASE"],
    api_key=os.environ["CHROMA_API_KEY"],
)
name, region = os.environ["COLLECTION"], os.environ["REGION"]
src = chroma.get_collection(name)
config = src.configuration
space = (config.get("spann") or config.get("hnsw") or {}).get("space", "l2")
order = "ASC" if space == "l2" else "DESC"  # euclidean: lower is closer
env = {k: v for k, v in os.environ.items()
       if k not in ("TOPK_API_KEY", "TOPK_PROJECT_ID")}
for q in src.get(limit=5, include=["embeddings"])["embeddings"]:
    q = [float(x) for x in q]
    want = src.query(query_embeddings=[q], n_results=10)["ids"][0]
    sql = (f"SELECT _id, vector_distance(embedding, '{json.dumps(q)}'::f32_vector) AS score "
           f"FROM \"{name}\" ORDER BY score {order} LIMIT 10")
    out = subprocess.run(
        ["topk", "sql", "--region", region, "-o", "json", "-f", "-"],
        input=sql, capture_output=True, text=True, check=True, env=env,
    ).stdout
    got = {json.loads(line)["_id"] for line in out.splitlines() if line.strip()}
    print(f"{len(set(want) & got)} / 10 shared")
PY
```

Expect close to 10 shared per query: both systems use approximate indexes. If counts differ, or most queries share fewer than 7, resume or re-run that collection's import, then verify again. If it still doesn't match, show the user the numbers.

### 8. Wrap up

Show the user a table per collection: Chroma count, TopK count and the average number of shared results. Then:

* Point out where their code calls Chroma (from step 2), and offer to switch those queries to the TopK SDK, following step 4 of [Migrate from Chroma](https://docs.topk.io/migrate/from-chroma.md). Before writing that code, install the TopK skill: `npx skills add topk-io/topk --skill topk`.
* The TopK SDKs need an API key: the user creates one at [console.topk.io/api-key](https://console.topk.io/api-key).
* Remind them of the Chroma Cloud dates if they apply: writes stop on November 22, 2026, so their application has to write to TopK before then.
* Tell them the export files in `chroma-to-topk/` contain their data, and can be deleted once they're satisfied.

## Troubleshooting

| Error or symptom | Fix |
| - | - |
| `chromadb` authentication error | Check the tenant ID, database name and API key with the user. |
| Import rejects an existing collection | A TopK collection with that name exists with a different schema. Ask the user whether to import under another name: change the collection name in every table header of the `.toml` file. |
| `--region is required` | Add `--region <REGION>` to the command. |
| `not logged in` or `session expired` | Run `topk login` again. |

Anything else: show the user the exact command and error message, and point them to [support](https://docs.topk.io/support).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.