Reference: environment variables
Every environment variable Cairn reads, grouped by concern. The canonical
templates are the .env.example files at the repo root and in apps/web,
apps/worker, and packages/db. Required means the app won't work without
it in production.
Database
| Variable | Required | Used by | Purpose |
|---|
DATABASE_URL | ✅ | web, worker, db | Postgres connection (pooled) used at runtime. |
DATABASE_URL_UNPOOLED | ✅ (migrations) | db | Direct (non-pooled) connection for drizzle-kit. |
DATABASE_PUBLIC_URL | optional | worker, db | Railway public-proxy alternative to the unpooled URL. |
Auth
| Variable | Required | Purpose |
|---|
BETTER_AUTH_SECRET | ✅ | Session encryption key. Generate: openssl rand -base64 32. |
BETTER_AUTH_URL | ✅ | App origin, e.g. http://localhost:3000. |
NEXT_PUBLIC_APP_URL | ✅ | Public app URL for the auth client + dashboard links. |
CAIRN_PRODUCTION_URL | local/preview proxy | Production Cairn origin that receives GitHub's registered callback. Ignored in production. |
OAUTH_PROXY_SECRET | OAuth proxy | Dedicated proxy key shared between production and local/preview. Do not reuse BETTER_AUTH_SECRET. |
OAUTH_PROXY_TRUSTED_ORIGINS | optional | Comma-separated preview or non-default local origins accepted by the proxy. Port 3000 is trusted automatically. |
GitHub user authorization (sign-in)
| Variable | Required | Purpose |
|---|
GITHUB_CLIENT_ID | ✅ | OAuth client ID. |
GITHUB_CLIENT_SECRET | production or direct OAuth | OAuth client secret. Not required by a local proxy client. |
Callback URL: <app-url>/api/auth/callback/github. To keep only the production
callback registered while developing locally, configure the OAuth proxy in both
environments. GitHub returns to production, which exchanges the code and relays
encrypted profile data to the local app.
GitHub App (repo access + webhooks)
| Variable | Required | Purpose |
|---|
GITHUB_APP_ID | ✅ | GitHub App ID. |
GITHUB_APP_SLUG | ✅ | App URL slug (used by the install flow). |
GITHUB_APP_PRIVATE_KEY | ✅ | RSA private key (PEM). Keep the \n escapes or quote the whole PEM. |
GITHUB_WEBHOOK_SECRET | ✅ | Verifies incoming webhook signatures. |
Permissions: contents:read, issues:write, pull_requests:write,
checks:write. Events: installation, installation_repositories, push,
pull_request. Webhook URL: <app-url>/api/github/webhook.
AI models
| Variable | Required | Purpose |
|---|
GOOGLE_GENERATIVE_AI_API_KEY | ✅ | Gemini — flow mapping + test generation. |
ANTHROPIC_API_KEY | optional | Claude — auto-fix. Usually set per-environment in the dashboard. |
Background jobs (Inngest)
| Variable | Required | Purpose |
|---|
INNGEST_EVENT_KEY | prod only | Inngest event key. Empty in local dev (keyless dev server). |
INNGEST_SIGNING_KEY | prod only | Inngest signing key. |
Artifact storage
| Variable | Required | Purpose |
|---|
STORAGE_DRIVER | ✅ | volume (local/mounted dir) — the self-host default. |
ARTIFACTS_DIR | ✅ (volume) | Where run videos/traces are written; mount a persistent volume here. |
ARTIFACTS_BEARER_TOKEN | ✅ | Shared token so the web app can proxy artifact reads from the worker. |
WORKER_ARTIFACTS_URL | when split | Worker's public URL, set when web + worker run on different hosts. |
Email (weekly recap)
| Variable | Required | Purpose |
|---|
RESEND_API_KEY | optional | Resend key. Without it, recaps are stored but not emailed. |
RECAP_FROM_EMAIL | optional | From address (a verified Resend domain). |
Landing page
| Variable | Required | Purpose |
|---|
NEXT_PUBLIC_GITHUB_REPO | optional | Public owner/repo for the Contribute button + star count. |
Optional / advanced
| Variable | Purpose |
|---|
CHAT_UPLOAD_DRIVER, BLOB_READ_WRITE_TOKEN | Chat image uploads (vercel-blob / r2). |
CAIRN_INSTRUMENT_* | Production API-capture SDK (Cairn dogfooding its own API tracking). |
PORT | Server port (web 3000, worker 3100). |