Configuration
Every option in oke.config.ts — three environments (dev · test · prod), drivers, images, i18n, tenancy, privacy, db sync, topology, ports, and console.
Complete reference for oke.config.ts. Options below match defineConfig. Driver maps use three keys: dev · test · prod.
import { defineConfig } from "okengine/config";
export default defineConfig({
// options below
});The one rule
Pin drivers and images in oke.config.ts for dev · test · prod. We test on what we deploy:
Docker-first local stack, PGLite for tests, same protocol ids in production.
Environments
| Key | When | Typical backends |
|---|---|---|
dev | oke dev (Docker Compose) | Same protocols as prod (Postgres, Redis, S3, SMTP, …) |
test | oke test / bun test | PGLite for SQL; memory / frozen / console elsewhere |
prod | Production deploy | Shared durable backends |
Missing dev pins fill from prod (fillDevFromProd). Only dev / test / prod keys are
valid — rename local → dev and docker → prod if you still have the old maps.
Quick start
Pin drivers for three envs
Pin only the env keys that differ from the built-in defaults — omitted keys
keep DRIVER_DEFAULTS. create-oke templates ship that sparse shape:
import { defineConfig } from "okengine/config";
export default defineConfig({
drivers: {
// Default vault.dev is "env"; pin the built-in store for Docker-first apps.
vault: { dev: "vault" },
},
});Or use a string shorthand
A bare string (or { driver, … } object) expands to all three envs:
drivers: {
signal: "redis", // → { dev: "redis", test: "redis", prod: "redis" }
},Prefer an explicit { dev, test, prod } map (or a partial override) when test
should differ from the default for that driver.
Run and test
oke dev # Docker Compose + host Bun · drivers.dev
oke test # bun test · NODE_ENV=test · OKE_PGLITE_URL=memory://Default driver maps
Built-in defaults (DRIVER_DEFAULTS) when a key is omitted:
| Map | dev | test | prod |
|---|---|---|---|
store.sql | postgres | pglite | postgres |
store.kv | redis | memory | redis |
store.files | s3 | memory | s3 |
signal | redis | memory | redis |
clock | postgres | frozen | postgres |
journal | postgres | memory | postgres |
vault | env | memory | vault |
channel.email | smtp | console | smtp |
channel.sms | — (opt-in) | — | — |
runs | files | memory | files |
store.index, channel.whatsapp / push, and ai have no single three-env default table — set them explicitly when you need them. create-oke templates pin vault.dev: "vault" (built-in) because the default dev driver is env.
Driver keys and ids
| Key | Shape | Driver ids |
|---|---|---|
store.sql | env driver map | postgres · pglite · memory |
store.kv | env driver map | memory · redis |
store.files | env driver map | memory · fs · s3 |
store.index | env driver map | memory · pgvector · meilisearch |
signal | env driver map | memory · redis (boot); postgres · nats fail loud until clients bind |
clock | env driver map | memory · postgres · file · frozen |
journal | env driver map | memory · file · postgres |
vault | env driver map | env · vault · memory · managed |
channel.email | env driver map | console · smtp · resend · sndr · taqnyat-mail |
channel.sms | env driver map | console · taqnyat · msegat · unifonic |
channel.whatsapp | env driver map | console · wa-cloud |
channel.push | env driver map | console · webpush · fcm |
ai | env driver map | mock · anthropic · openai-compatible · bedrock · vertex |
runs | env driver map | memory · files (Parquet + DuckDB at .oke/runs) · postgres · clickhouse |
prod | string[] | flat protocol list for the Manifest — nested maps are preferred |
Safety rules
defineConfig rejects unsafe pins:
sqliteis removed — usepostgres(dev/prod) orpglite(test).drivers.store.sql.testmust bepglitewhen set — real Postgres semantics in tests.
Rich driver objects
sql: {
prod: { driver: "postgres", pool: { max: 20 }, replicas: ["postgres://ro-1/db"] },
},| Field | Type | Meaning |
|---|---|---|
url | connection string | Overrides the env-var resolution |
pool | { max?, min? } | SQL pool sizing |
replicas | string[] | Read-only routing targets (read flows only) |
images
Nested pins by element role — vendor choice lives here, never in driver ids:
images: {
store: {
sql: "postgres:18-alpine",
kv: "redis:8-alpine",
files: "rustfs/rustfs:1.0.0-rc.5",
},
channel: { email: "axllent/mailpit:v1.31.1" },
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
// proxy: "caddy:2-alpine",
},Omitted image keys mean no container for that role. When both store.sql and pgdog are pinned, DATABASE_URL points at PgDog — see Store.
For store.kv, pin Redis (default), Valkey, or Dragonfly — driver id stays redis.
{ durable: true } KV lives in SQL (oke_kv on DATABASE_URL), not a second Redis image.
Compose does not manage AI inference — OpenRouter or BYO
OKE_AI_URL (Models). For proxy, see Caddy,
Traefik, or nginx.
i18n
| Option | Type | Default | Meaning |
|---|---|---|---|
locales | string[] | ["en"] when omitted | Supported locales |
default | string | "en" when omitted | Fallback locale (channel templates, fx.t) |
dir | record | — | Per-locale direction: "ltr" | "rtl" |
i18n: { locales: ["en"], default: "en" },
// or with Arabic: { locales: ["en", "ar"], default: "en", dir: { ar: "rtl" } }tenancy
oke.config.ts tenancy is isolation posture (how rows are separated). Identity —
who the tenant is — is gate.auth.tenant on Gate.
| Option | Type | Meaning |
|---|---|---|
isolation | "row" | "schema" | "database" | How tenants are separated in the store |
resolve | string | function | Observational resolver (isolation-only manifests) |
privacy
Presence of this block turns CORE privacy tooling on in the Console — not a .plug() call.
privacy: {},runs
Runs retention and redaction — not the same key as drivers.runs.
| Option | Type | Meaning |
|---|---|---|
keep | string | "forever" | Delete Parquet partitions older than this (7d in dev, 30d in prod) |
redact | Record<string, string> | Field → retention duration; presence turns privacy on |
db
Domain schema sync for oke db push | generate | migrate (Drizzle). Unrelated to oke schema generate.
| Option | Default | Meaning |
|---|---|---|
autoPush | true | Auto-run db push on schema change under oke dev; forced off in prod |
config | "drizzle.config.ts" | Path to the drizzle-kit config |
declare | "src/db/schema.decl.ts" | Abstract schema module (store.schema.table exports) |
generated | "src/db/schema.drizzle.ts" | Where oke db emits dialect Drizzle |
entry | src/app.ts | App entry for collecting plugin table contributions |
topology
| Value | Meaning |
|---|---|
"monolith" | One process serves everything (default posture) |
"services" | Split deployment units derived from the Manifest |
ports
| Option | Default | Surface |
|---|---|---|
app | 6530 | Backend |
console | 6533 | Console |
mcp | 6535 | MCP |
console
| Option | Type | Default | Meaning |
|---|---|---|---|
prod.enabled | boolean | — | Serve the Console in prod |
prod.auth | "required" | "optional" | "none" | — | Access requirement |
Troubleshooting
The sqlite driver is gone. Pin postgres for dev/prod and pglite for test. Edit the
file by hand — rename the env keys to dev / test / prod first.
Tests use PGLite so SQL semantics match Postgres. Set test: "pglite" (or omit the key and keep
the default). Do not use memory or postgres for store.sql.test.
There is no soft-compat. Rename env keys to dev / test / prod and replace sqlite with
postgres / pglite. oke mode was removed — oke dev always starts Docker Compose.
The files driver needs @duckdb/node-api. create-oke templates add it. Install with bun add @duckdb/node-api if an older app is missing the peer.
Learn more
- CLI —
oke dev·oke test·oke db - Environment Variables — URL and secret resolution
- Store — what the store drivers back
- i18n — locale catalogs beyond the config block