Self-Hosting Quickstart
Run your own CortexDB server with one docker run, then store and recall your first memory against localhost — the recommended way to start.
Self-hosted CortexDB is for customers
Self-hosted releases from 0.9.0 on, including the one these docs describe, are available to customers through the customer portal, with a company license; talk to us to become one. The last public release, 0.8.21, is on cortexdb.ai/download. To use this release today without running a server, start on CortexDB Cloud.
Self-hosting is the recommended way to run CortexDB. You get the same server the cloud runs, your data never leaves your infrastructure, and there's no per-token cost. This page takes you from nothing to a running server with a stored-and-recalled memory in about five minutes.
The quickest path
Not running a server at all is quicker still: CortexDB Cloud is the same release at
https://api.cortexdb.ai, free to start. Customers install a server with the installer on the customer
portal's Releases page, which also carries their company's license; the steps by hand follow.
The public release is different
cortexdb.ai offers CortexDB 0.8.21, the last public release, as docker run cortexdb/cortexdb:v0.8.21 from
Docker Hub, with no license and no portal. Customer releases (0.12.1 and later) come only from
customer.cortexdb.ai: the image is a file you docker load, it is tagged with its exact version (there is no
:latest to pull), and it needs your company's license (Your license). Never
mix the two: a docker pull cortexdb/cortexdb:latest fetches the public release, not yours.
Prerequisites
- A container runtime — Docker (or Podman). CortexDB ships as a single image,
cortexdb/cortexdb. - An embedding provider — vector recall needs one. Either an OpenAI-compatible API key (used
only for embeddings) or a local Ollama (fully local, no external
calls — see Fully local below). Both are equally supported: use the
OpenAI key on modest hardware (a laptop, no GPU, limited RAM or disk) or for the simplest setup,
and local Ollama on a high-end machine or when vectors must stay on the box. Decide before your
first write; the choice is pinned to the data directory
and switching later is an offline rebuild. A container with an
embedding endpoint configured but no credential refuses to start (
FATAL: an explicit CORTEX_EMBEDDING_URL requires CORTEX_EMBEDDING_API_KEY, OPENAI_API_KEY, or LLM_API_KEY) instead of silently serving meaningless mock vectors; the image sets an OpenAI embedding URL by default, so the plaindocker runneeds a key.CORTEX_EMBEDDING_PROVIDER=mockis the explicit opt-in for control-path tests. - ~2 GB RAM and a data volume. A single node handles ~10M events on commodity hardware; everything
persists under
/data. - Optional, only if you want them: an answer lane (
CORTEX_ANSWER_*) to enable/v1/answer, and enrichment to populate the Facts/Beliefs/Understanding layers — both off by default. See Self-hosting defaults.
1. Start the server
Load the image from the release page first (its "Run the steps by hand" block downloads it, checks the
SHA-256 and runs docker load). docker images cortexdb/cortexdb shows the tag it loaded.
export CORTEX_LICENSE='<your license>' # in the release page's commands
CORTEXDB_IMAGE=cortexdb/cortexdb:v0.12.8 # the tag docker load printed
docker run -d \
--name cortexdb \
--restart unless-stopped \
--stop-timeout 120 \
-p 127.0.0.1:3141:3141 \
-v cortexdb-data:/data \
-e CORTEX_LICENSE \
-e CORTEX_INSECURE_NO_AUTH=1 \
-e CORTEX_EMBEDDING_API_KEY=$OPENAI_API_KEY \
"$CORTEXDB_IMAGE"That's the whole install. The container ships with every field at its compiled default: single-node, the
v1 API on :3141, data persisted to the cortexdb-data volume. --restart unless-stopped brings the
server back after a console restart (which exits with code 75) or a crash, and --stop-timeout 120 gives
it the 120 seconds the server needs for a graceful stop (Docker's default is 10 seconds; see
Upgrading).
Why an OpenAI key, and why as CORTEX_EMBEDDING_API_KEY?
It's used only for embeddings (vector recall needs a real embedding provider; the
server exits at startup rather than run on meaningless mock vectors). Passing it as
CORTEX_EMBEDDING_API_KEY keeps it embeddings-only. Passed as plain OPENAI_API_KEY, the image's baked
defaults also switch on entity extraction (a gpt-4o-mini call per write) and the gpt-4.1 verifier
lane, which you may not want on a first run.
Prefer to keep everything local? Point embeddings at a local Ollama instead — see
Fully local, no external keys below.
Auth: CORTEX_INSECURE_NO_AUTH is dev-only
CORTEX_INSECURE_NO_AUTH=1 makes the server serve requests with no token (as user:local, or as the
named X-Cortex-Actor) — the frictionless path for local development. The flag does not restrict the
bind; the -p 127.0.0.1:... mapping is what keeps it on loopback only. Before
exposing the port, drop that flag and set -e CORTEX_API_KEY=<a strong secret> instead; the value
itself becomes your bearer credential (Authorization: Bearer <secret>). Note: if you set neither
on a network-exposed bind, the server refuses to serve open — it auto-generates a key and prints it in
the boot log, and every request needs it. See Security & Compliance.
On a network, send the key with every request
Every deployment preset requires the key: a request carrying only an X-Cortex-Actor header gets
401 MISSING_TOKEN.
2. Confirm it's healthy
curl http://localhost:3141/v1/admin/health
# {"status":"healthy","version":"vX.Y.Z"} <- the release you installed, e.g. the one on your Download page
curl http://localhost:3141/v1/admin/ready
# ... "degraded": false → real embeddings are working (not mock)If ready reports "degraded": true, the embedding provider is failing (for example a dead key
returning 401) or you opted into mock embeddings — check the embeddings block for the provider's
error text. A container with no embedding credential at all does not get this far: it exits
at startup (see Prerequisites).
Readiness is outcome-based — gate deploys on it, not health
/v1/admin/ready reports what real provider calls actually did. Its embeddings check distinguishes
mock, failing (a configured key returning 401 on every call), and healthy — so a dead key
marks the server degraded and surfaces the provider's error text instead of silently returning empty
recall. health only tells you the process is up; always gate container healthchecks and deploys on
ready.
3. Store and recall your first memory
No token is needed because the server was started with CORTEX_INSECURE_NO_AUTH=1 (dev mode). Pick your
surface — on a keyed server, add -H "Authorization: Bearer $CORTEX_API_KEY" (curl) or
bearer=… (SDK):
curl
# Capture. ?wait=indexed returns once the event is searchable, so the recall below can't race the write.
# Keep the "id" in the answer: it is the original event ID.
curl -sfS -X POST "http://localhost:3141/v1/experience?wait=indexed" \
-H "X-Cortex-Actor: user:local" -H "Content-Type: application/json" \
-d '{
"scope": "org:demo/user:local",
"modality": "conversation",
"content": { "kind": "message", "role": "user",
"text": "We migrated the payments service to CockroachDB. Timeline is Q2 2026." },
"context": { "observed_at": "2026-05-16T10:42:00Z" },
"idempotency_key": "decision-payments-001"
}'
# Recall
curl -sfS -X POST http://localhost:3141/v1/recall \
-H "X-Cortex-Actor: user:local" -H "Content-Type: application/json" \
-d '{ "scope": "org:demo/user:local", "view": "holistic",
"query": "What database are we using for payments?", "diagnostics": "none" }'Python
pip install cortexdbaifrom cortexdb.v1 import V1Client
# Point at your self-hosted server. In local no-auth mode, no bearer token is needed.
client = V1Client(api_url="http://localhost:3141", actor="user:local")
scope = "org:demo/user:local"
client.experience(
scope=scope,
text="We migrated the payments service to CockroachDB. Timeline is Q2 2026.",
observed_at="2026-05-16T10:42:00Z",
idempotency_key="decision-payments-001",
wait="indexed", # block until it's searchable, for a clean first recall
)
pack = client.recall(scope=scope, view="holistic",
query="What database are we using for payments?", diagnostics="none")
print(pack.get("context_block", ""))TypeScript
npm install cortexdbaiimport { V1Client } from "cortexdbai/v1";
const client = new V1Client({ apiUrl: "http://localhost:3141", actor: "user:local" });
const scope = "org:demo/user:local";
await client.experience(scope, {
text: "We migrated the payments service to CockroachDB. Timeline is Q2 2026.",
role: "user",
observedAt: "2026-05-16T10:42:00Z",
idempotencyKey: "decision-payments-001",
}, { wait: "indexed" });
const pack = await client.recall(scope, { view: "holistic",
query: "What database are we using for payments?", diagnostics: "none" });
console.log(pack.context_block);4. Verify it — and where things live
A quick "did it actually work?" checklist:
- Readiness, not liveness.
curl http://localhost:3141/v1/admin/ready→"degraded": false. If it'strue, the embedding provider is failing or mocked — fix it before trusting recall. - Read-your-writes. The recall in step 3 should return your text in
context_block. (It usedwait="indexed", so the event is searchable by the time the write returns.) - Where your data lives. Everything — WAL, RocksDB, indexes, blobs — is under
/data, persisted to thecortexdb-dataDocker volume. Back it up with a verified cold backup. - Boot diagnostics / logs.
docker logs cortexdbshows the pinned embedding provider, the auth posture, and theconfig_lintdump (what actually loaded). Grep it when something's off:docker logs cortexdb 2>&1 | grep -iE "embedding|auth|answer|degraded" - The Admin Console. Open
http://localhost:3141/in a browser — CortexDB ships a built-in operator UI (Overview, Memories, Observability, Logs, Settings, …). See Admin Console.
Common first-run issues
degraded: true → no real embedding provider (set a key or point at Ollama). 401 MISSING_TOKEN on a
write → the server isn't in no-auth mode; start it with CORTEX_INSECURE_NO_AUTH=1 (dev) or send
Authorization: Bearer $CORTEX_API_KEY. Empty facts() / no /v1/answer → expected on a content-only
instance; enable enrichment / the answer lane (defaults).
What you get by default
Your instance runs in content-only mode out of the box: event capture, episodes, and BM25 + vector +
RRF recall are on. Blob extraction (it needs content processors configured), the LLM-derived layers
(Facts, Beliefs, Understanding), the knowledge graph, cross-encoder rerank, and /v1/answer are
opt-in — see
Self-hosting defaults for exactly what's on and how to enable the rest.
Fully local, no external keys
To run with no external API calls at all, point embeddings at a local Ollama. This is the right choice on a high-end machine (spare CPU and RAM, ideally a GPU) or when the text you store must never leave the box; on a modest machine the OpenAI key above is the lighter option, and the two are otherwise equivalent. Start Ollama and pull the model before the first write, because the provider is pinned to the data directory on first boot:
# On the host: ollama pull nomic-embed-text
docker run -d --name cortexdb --restart unless-stopped --stop-timeout 120 \
--network host -e CORTEX_V1_API_ADDR=127.0.0.1:3141 -v cortexdb-data:/data \
-e CORTEX_LICENSE \
-e CORTEX_INSECURE_NO_AUTH=1 \
-e CORTEX_EMBEDDING_PROVIDER=ollama \
-e CORTEX_EMBEDDING_URL=http://127.0.0.1:11434 \
-e CORTEX_EMBEDDING_MODEL=nomic-embed-text \
-e CORTEX_EMBEDDING_DIMS=768 \
-e CORTEX_EMBEDDING_API_KEY=ollama \
"$CORTEXDB_IMAGE"Ollama listens on 127.0.0.1 by default, which a container on Docker's own network can't reach, so the
container shares the host's network (--network host, Linux) and CORTEX_V1_API_ADDR keeps CortexDB on
this machine only. CORTEX_INSECURE_NO_AUTH=1 is the same local-only choice as above: without it, or an
API key, the first write is refused. The installer's "Local Ollama" option sets all of this and checks the model is pulled.
To also get natural-language answers (/v1/answer) and the Facts/Beliefs layers locally, wire the
answer lane and enrichment to Ollama too — see LLM & Answer and
Self-hosting defaults.
Upgrading
CortexDB upgrades are a container image swap against the same data volume: stop the server with a
120-second grace (docker stop -t 120 cortexdb), then start the new image with the same flags and volume.
The full procedure, what each release changes for an existing deployment, and how to roll back are on
Upgrading.
Next steps
- Self-hosting defaults & prerequisites — default vs opt-in, per feature
- Configuration — the file / env / CLI model
- Profiles & Presets — copy-paste configs (incl. an Enterprise profile)
- Backups & Disaster Recovery · Security & Compliance
- Python · TypeScript · CLI · MCP server