Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Every variable is prefixed RUNTIME_, so env | grep RUNTIME_ is a complete answer. There is no configuration file: the environment is read once, at start-up, in the binary.

runtime config prints what actually took effect and exits — because “which value won” is a question asked at the worst possible moment.

Every variable

VariableDefaultNotes
RUNTIME_DATABASE_URLRequired to serve
RUNTIME_APP_ADDR0.0.0.0:8080End-user traffic
RUNTIME_ADMIN_ADDR127.0.0.1:9090Widen in a container; never route to it
RUNTIME_DATABASE_MAX_CONNECTIONS10See below
RUNTIME_DRAIN_DELAY5Seconds. See below
RUNTIME_OIDC_ISSUERBoth or neither
RUNTIME_OIDC_AUDIENCEBoth or neither
RUNTIME_OTLP_ENDPOINTUnset exports to stdout
RUNTIME_ENVIRONMENTdevelopmentTags every span, metric and log
RUNTIME_LOGinfotracing filter directives
RUNTIME_LOG_FORMATjsonOr pretty, for a laptop

The app and admin addresses must differ, and the loader refuses to start otherwise.

The pool size is the capacity knob

RUNTIME_DATABASE_MAX_CONNECTIONS is per process. The number to reason about is not this one but this one times the replica count, against PostgreSQL’s own max_connections. A value that looks modest per pod is how a scale-up takes the database down.

Requests that arrive with the pool saturated wait five seconds for a connection and then fail. That is deliberately shorter than the thirty-second request timeout: a brief slowdown should produce prompt errors that readiness and your metrics both show, not a pile of requests all waiting out the full timeout and outliving the slowdown that caused them.

Authentication is both or neither

RUNTIME_OIDC_ISSUER=https://login.example.com/realms/acme
RUNTIME_OIDC_AUDIENCE=runtime

Set one without the other and the runtime refuses to start. An issuer with no audience accepts tokens minted for every other service that provider serves — a different tenant, a different application — and it does so silently.

Keys are discovered from the issuer’s /.well-known/openid-configuration at start-up, so a misconfigured issuer stops a deploy rather than becoming a 500 on whoever calls first.

With neither set, no bearer token can be verified: every authenticated request is a 401 and only the model’s anonymousRole reaches anything. If the model declares no anonymous role either, the runtime refuses to start — a process that could serve nobody is the most expensive kind of healthy.

What the runtime never reads

There is no configuration file, no .env loading, and no remote configuration service. The .env.example in the runtime repository is the documented variable list, not a mechanism — nothing loads it.