Skip to main content
Configuration is environment variables only. There is no config file to mount and no setting that lives in the database.

Required

string
required
A Postgres connection string. Postgres 17 or newer, 18 recommended. Use TLS (sslmode=require) unless you connect over a Unix socket.Connect through a session-mode pooler, not a transaction-mode one: the reconciler’s advisory lock needs a session. On a pooled provider that means the session port, and never the transaction port.
string
required
A base64 32-byte key that seals customers’ cloud credentials.
The example key shipped for local development is explicitly refused outside development.

URLs

string
default:"http://localhost:8080"
Where browsers, GitHub and runner machines reach the API. Must be https outside development — enforced at startup, not by convention, because cache-enabled runners fetch the proxy and its credentials from here.
string
default:"http://localhost:3000"
The dashboard. GitHub sign-in returns here.
string
default:"http://localhost:3000"
Comma-separated browser origins allowed to call the API. Include DASH_URL.
Serve the dashboard and the API on the same site — app.example.com and api.example.com — so the session cookie is sent. Different sites means no session.

GitHub App

See The GitHub App for where each value comes from. Without these the dashboard still loads, but sign-in, webhooks and launches are off.

Runner lifecycle

Defaults shown. Most deployments change none of them.

Service

Never set in production

The dashboard

One variable, and it is inlined when the app is built — so set it in the build environment, not only at runtime:
A production build with the localhost default fails on purpose.

Credentials key

The sealing key deserves its own rules.
1

Keep it outside the database

It is the only thing that can open the sealed cloud credentials. Holding it next to them defeats the point.
2

Back it up as you would a root key

Losing it loses every connected cloud. Recovery is reconnecting each one by hand.
3

Rotate with two keys, never by replacement

List the new key first and the old one after a comma, deploy, reconnect each cloud — which re-seals with the new key — then drop the old one.

Running several replicas

Safe, and recommended. Launchers claim runners with row locks, and the reconciler elects a leader through a Postgres advisory lock, so exactly one replica reconciles at a time. Run the migration once per release, before the new replicas start:

Health and documentation