What it documents
Each variable below has a name, the subsystem that reads it, default value (literal fallback in the code, or— when there is none), and a one-line purpose. Variables are grouped by domain so an operator can configure a single subsystem without scrolling the whole page. Subsystem deep-dives live on /self-host/configure/configuration-reference and /self-host/deploy/helm-reference; this page indexes everything in one place and cross-links to the deep-dive where one exists.
Quick start
The minimum to boot the platform locally:DATABASE_URL is the only variable required outside production; the other five become required when NODE_ENV=production.
Production checklist (in addition to the six above):
REDIS_URL— required for caching, rate limiting, and the background worker queue.CORS_ALLOWED_ORIGINS— must be a non-empty, non-wildcard list in production, or env validation throws at startup and the process refuses to boot.EVENT_PUBLISHER+ the matching backend group (KAFKA_*,MSK_*,EVENTBRIDGE_*,KINESIS_*) — defaults toredis.INTERACTION_STORE+ the matching backend group (SCYLLA_*,DYNAMODB_*,KEYSPACES_*) — defaults topg.SEARCH_INDEX+OPENSEARCH_*when running OpenSearch — defaults topg.OTEL_EXPORTER_OTLP_ENDPOINT— when shipping traces.- A SIEM block (
SIEM_BACKEND+SIEM_ENDPOINT+ optionalSIEM_API_KEY/SIEM_SOURCETYPE/SIEM_INDEX) — when shipping audit logs to Splunk, Datadog, or Elastic.
How it works
Env validation runs at process startup (eagerly invoked from the database layer). Two passes:- Presence — the validator iterates the required-vars list. Production-required keys missing → throw. Development-required keys missing → warn-only.
- Format — the validator checks
DATABASE_URLstarts withpostgresql://,REDIS_URLstarts withredis://orrediss://, the listen port is in the legal range[1, 65535],CORS_ALLOWED_ORIGINSis non-empty and non-wildcard in production, and any optional-boolean vars are literally the string"true"or"false".
NEXT_PHASE === "phase-production-build") skips validation entirely so next build does not need production secrets.
Subsystem env reads happen lazily at first use:
- The platform’s dependency-injection container reads
EVENT_PUBLISHER,INTERACTION_STORE, andSEARCH_INDEXonce-per-process to pick the backend, then reads the backend-group vars to construct the client. - The Postgres pool reads
PG_POOL_MAXonce at module load. - Per-request env reads (such as
NEGOTIATION_GLOBAL_KILLandALLOW_UNSIGNED_WEBHOOKS) hitprocess.envon every call. Operators changing those vars need a process restart only when the read is module-scoped, not per-request.
Reference
Database and migrations
Auth and MFA
Network, CORS, and CSP
number
HTTP listen port for the platform process. Defaults to Next.js’
3000 when unset. Validated to be an integer in the legal port range [1, 65535].Redis, caching, and rate limits
string
Upstash REST API base URL (
https://<id>.upstash.io). Distinct from REDIS_URL, which is the standard Redis-protocol connection. Set when you provision an Upstash database; not currently read by platform code (reserved for future REST-API features), but safe to leave configured.string
Upstash REST API token. Companion to the REST URL; not currently read by platform code.
Upstash quota awareness: the free tier is 500K Redis commands/month. WithWORKER_INPROCESS=1and idle queues, five BullMQ workers polling Upstash burn ~1.3M ops/month with zero useful work. See worker-mode-and-cron-drain runbook for the cost math and theWORKER_INPROCESS=0+ cron-driven drain pattern that fits inside the free tier.
Event publisher (Kafka / MSK / EventBridge / Kinesis / Redpanda)
EVENT_PUBLISHER selects the backend; only the matching group is read.
AI providers
The platform uses generic env keys (provider, model, API key, base URL) rather than vendor-native keys. Vendor-native names like the OpenAI or Anthropic API-key environment variables are not read directly — instead, the configured key is passed into the SDK constructor from the generic env key after a Settings-UI override check. Tenant-level overrides in the Settings UI take precedence over env. The four generic AI env keys are dereferenced via a constant map at runtime — the static drift checker can’t trace this indirection, so the keys are documented below as<ParamField> entries (the same is true for several others on this page).
string
default:"google"
Provider selector. Acceptable values:
google, anthropic, openai, ollama, lm_studio, bedrock.string
default:"gemini-2.5-flash"
Model id passed to the provider SDK.
string
API key for the selected provider.
string
Override base URL — required for Ollama (default
http://127.0.0.1:11434/api) and LM Studio.Scoring and ONNX
Interaction store (Postgres / DynamoDB / Keyspaces / ScyllaDB)
INTERACTION_STORE selects the backend; only the matching group is read.
Search index (Postgres / OpenSearch)
Storage and attachments
Email and outbound
Governance, approvals, and license
string
RSA private key (PEM, PKCS8) for signing customer licenses. Read by the license-generator script — script-side only, not by the running platform. When unset, the script auto-generates a fresh RSA key pair on each run rather than failing. The matching public key ships embedded in the platform for verification.
Worker, outbox, and seed
number
default:"2000"
Outbox polling interval in milliseconds. Read by the outbox publisher worker via the positive-int env helper.
number
default:"15000"
Max time (ms) to wait for in-flight publishes to drain on shutdown. Read by the outbox publisher worker via the positive-int env helper.
Cron tier
Observability — tracing, metrics, logs
The structured logger pairs with the platform’s per-call error-logging helper. The helper mints a per-call UUID
errorId, sanitizes the error message, attaches an optional meta block, and returns the errorId for the caller to surface (HTTP response body, downstream worker telemetry, audit row). Use it for any caught error a SIEM or operator may need to correlate later. Adoption is incremental — the API-route layer and the Outbox publisher worker already mint errorId per failed tick; other workers still emit bare logger error calls and are tracked for migration in the engineering residuals list.
Audit + SIEM
Provenance, supply chain, and signing
string
Cosign-format private key bytes (the contents of
cosign.key, not a file path). Cosign itself dereferences the bytes via the env:// URI scheme passed on its CLI; the platform passes the env-var name through. When unset, every /api/v1/decisions/:id/provenance response returns X-Provenance-Signature: unsigned. Required for production. Install via AWS Secrets Manager (cloud) or local key file (self-host) — see Provenance signing install guide.string
Passphrase paired with the cosign key. Required when the key was generated with a passphrase (the default for
cosign generate-key-pair). Set in env so the cosign subprocess inherits it; the platform itself does not read it.Webhooks and inbound channels
Multi-region and tenant routing
MCP server (CLI / SDK side)
Flow runtime
External AI/transform endpoints (Flow runtime)
These four endpoint names are declared in the registry theexternal-model-call transform consults at runtime. The actual process.env lookup happens inside the call helper, dispatched off the registry entry’s name field — the static drift checker can’t trace this through the indirection. Operators must set the corresponding env var before invoking the transform; if unset, the transform throws a missing-endpoint error and the row fails fast.
string
External geo-resolution model URL.
string
External language-detection model URL.
string
External sentiment-scoring URL.
string
External embedding-vector URL.
Playground and demo
Python ml-worker
The Python FastAPI service for ML training and ONNX scoring reads only two env vars.number
default:"8000"
FastAPI listen port for the Python ml-worker (Python-side; not read by the TypeScript platform).
Test-only
These keys are read only by the test runner. Operators should not set them in production.string
default:"test-ch7-key"
Integration-test API key. Read by the decision-flow integration test suite.
string
default:"5a9904b9-4f75-4c4b-a04d-ff826…"
Integration-test tenant id. Read by the decision-flow integration test suite.
string
default:"http://localhost:3000"
Base URL used by integration-test HTTP calls. Read by the sample-data end-to-end integration test.
string
Set by the Vitest test runner. Production code branches on its presence to skip side effects in tests.
Configuration
Loading order
Next.js picks up env files in this order, last-write-wins (per Next.js framework defaults):.env.env.local(gitignored — local overrides).env.${NODE_ENV}(e.g..env.production).env.${NODE_ENV}.local- Process environment (
process.env)
.env.example template ships with the platform — copy it to .env.local for local dev and to a secret manager (Kubernetes Secret, AWS SSM, etc.) for production.
Kubernetes — ConfigMap vs Secret
The shipped Helm chart splits non-secret runtime config from secrets:- Non-secret runtime config (
NODE_ENV,LOG_LEVEL,EVENT_PUBLISHER,INTERACTION_STORE,SEARCH_INDEX,RLS_AUTO_ENABLE,WORKER_CONCURRENCY,OUTBOX_*,SLOW_API_THRESHOLD_MS,RETRAIN_EVERY_N,OPENSEARCH_INDEX_PREFIX,OPENSEARCH_TLS_ENABLED) lives in the chart’s ConfigMap template. - Secrets (
DATABASE_URL,REDIS_URL,NEXTAUTH_SECRET,JWT_SIGNING_SECRET,CONNECTOR_ENCRYPTION_KEY*,WEBHOOK_SIGNING_SECRET,API_KEY_PEPPER,WORKER_SECRET,INTERNAL_SERVICE_SECRET,CRON_SECRET,CRON_TOKEN,KAFKA_SASL_PASSWORD,MSK_SASL_PASSWORD,*_SECRET_ACCESS_KEY,*_PASSWORD,SIEM_API_KEY,WHATSAPP_APP_SECRET, plus the KAIREON_LICENSE_PRIVATE_KEY and COSIGN_KEY documented above) live in the chart’s Secret template.
/self-host/deploy/helm-reference for the full chart values map.
Rotation guidance
Honest limits
- TS-only vs Python ml-worker — Of the documented variables, only
DATABASE_URLis read by both the TypeScript platform and the Python ml-worker. The ml-worker port (documented above as a<ParamField>) is Python-only. The platform talks to the ml-worker viaML_WORKER_URL+ML_WORKER_API_KEY(HTTP); the two processes do not share env vars beyondDATABASE_URL. - Once-at-boot vs per-request reads — Most env vars are read once during module load (DI container, database pool, AI provider config, encryption keys). A handful are read per-request:
NEGOTIATION_GLOBAL_KILLandALLOW_UNSIGNED_WEBHOOKS. For the rest, a process restart is required after changing the value. - Deprecated / soft-deprecated —
CRON_TOKENis the legacy alias forCRON_SECRET. Every cron route now resolves its secret asCRON_SECRET || CRON_TOKEN, so both authorize the whole cron tier; preferCRON_SECRETfor new deployments. Both are kept untilCRON_TOKENis removed. - Internal-only flags — operators should not set —
_SEED_FROM_WORKERis set by the seed-executor itself before its internal HTTP call. Setting it manually breaks reentrancy detection. - Test-only flags in production —
MFA_ENFORCEMENT_DISABLED,ALLOW_UNSIGNED_WEBHOOKS, plus the four test-only<ParamField>entries above (test API key, tenant id, base URL, and the Vitest runner-detection flag) must not appear in any production environment.ALLOW_UNSIGNED_WEBHOOKSis hard-blocked whenNODE_ENV=production; the others are not enforced — operator discipline only. - License private key is script-side — Read only by the license-generator script, never by the running platform (see the KAIREON_LICENSE_PRIVATE_KEY
<ParamField>above). The platform verifies licenses with the matching public key embedded in source. When unset, the script auto-generates a fresh RSA key pair on each run rather than failing. - AI provider env keys are tenant-overridable — Tenant-level AI settings in the Settings UI take precedence over the four AI-provider env keys documented as
<ParamField>entries above (provider, model, API key, base URL). The env vars are only the fallback when no DB-level setting is configured. - Environment variables not yet wired for the AI sidebar metadata — Two AI-sidebar reserved keys are declared in the AI-env constant map but currently have no read in the platform. They are reserved keys;
<ParamField>entries for both follow.
boolean
Reserved AI-sidebar feature flag. No reader in the platform yet.
number
Reserved AI-sidebar rate-limit knob. No reader in the platform yet.
Related
- Configuration Reference — narrative deep-dive on the most-used variables (database, cache, integrations).
- Helm Reference — chart values map and ConfigMap/Secret split.
- Security Hardening — production-only secret-rotation requirements.
- Installation Guide — step-by-step deploy with the required env-var subset.
- Infrastructure Backends —
EVENT_PUBLISHER,INTERACTION_STORE,SEARCH_INDEXbackend selection. - ML Worker Deployment —
ML_WORKER_*env vars. - MCP Integration —
KAIREON_API_URL,KAIREON_API_KEY,KAIREON_TENANT_ID,MCP_ALLOW_WRITES. - EventBridge Setup —
EVENTBRIDGE_*configuration.