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-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.
Prerequisites
- A container runtime — Docker (or Podman). CortexDB ships as a single image,
cortexdb/cortexdb. - An embedding provider — vector recall needs one, or the server falls back to mock embeddings and recall is meaningless. Either an OpenAI-compatible API key (used only for embeddings) or a local Ollama (fully local, no external calls — see Fully local below).
- ~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
docker run -d \
--name cortexdb \
-p 127.0.0.1:3141:3141 \
-v cortexdb-data:/data \
-e CORTEX_INSECURE_NO_AUTH=1 \
-e OPENAI_API_KEY=$OPENAI_API_KEY \
cortexdb/cortexdb:latestThat'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.
Why the OPENAI_API_KEY?
It's used only for embeddings (vector recall needs a real embedding provider — without one the server runs on mock embeddings and recall is meaningless). It is not used for answers or extraction here. 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 every request as user:local with no token — the
frictionless path for local development, and the -p 127.0.0.1:... binds it to 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.
2. Confirm it's healthy
curl http://localhost:3141/v1/admin/health
# {"status":"healthy","version":"v0.9.9"}
curl http://localhost:3141/v1/admin/ready
# ... "degraded": false → real embeddings are working (not mock)If ready reports "degraded": true, the server is on mock embeddings (recall would be meaningless) —
check that your embedding provider/key is set.
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
curl -sfS -X POST http://localhost:3141/v1/experience \
-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, {
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",
}, { 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, you're on mock embeddings — fix the embedding provider 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, BM25 + vector +
RRF recall, and blob extraction are all on. 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:
# On the host: ollama pull nomic-embed-text
docker run -d --name cortexdb \
-p 127.0.0.1:3141:3141 -v cortexdb-data:/data \
-e CORTEX_EMBEDDING_PROVIDER=ollama \
-e CORTEX_EMBEDDING_URL=http://host.docker.internal:11434 \
-e CORTEX_EMBEDDING_MODEL=nomic-embed-text \
-e CORTEX_EMBEDDING_DIMS=768 \
-e CORTEX_EMBEDDING_API_KEY=ollama \
cortexdb/cortexdb:latestTo 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 — your data lives in the volume, not the image:
docker pull cortexdb/cortexdb:latest # or pin a version, e.g. :v0.9.9
docker rm -f cortexdb
docker run -d --name cortexdb -p 127.0.0.1:3141:3141 -v cortexdb-data:/data \
-e CORTEX_INSECURE_NO_AUTH=1 -e OPENAI_API_KEY=$OPENAI_API_KEY \
cortexdb/cortexdb:latest # same flags + the SAME volumeMost releases are drop-in — no data migration, and existing data directories work as-is. Check the
release notes at cortexdb.ai/changelog for anything that isn't (and
for what each version changes). Take a verified cold backup before a major
upgrade, and re-check GET /v1/admin/ready after.
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
Self-Hosting
Running CortexDB yourself is the recommended path — the same server the cloud runs, on your own infrastructure. Start here.
Self-Hosting Defaults & Prerequisites
What a default self-hosted CortexDB instance does out of the box, and which features are opt-in — enrichment, cross-encoder rerank, and the knowledge graph.