Skip to content

Configuration

Every setting is an environment variable, and they fall into three tiers. All of them are validated when the server starts, and a start that fails lists every problem rather than the first one.

To see what a running instance is configured for, call GET /api/config-report as a global administrator. It reports state, never values.

On Cloudflare, every credential below is a Worker secret rather than a plain variable. The Cloudflare page lists which is which.

The server refuses to serve without these.

Variable Purpose
APP_URL The public base URL. Every link in every email, every OAuth redirect and every webhook registration is built from it
OAUTH_ENCRYPTION_KEY A 32-byte secret. Encrypts stored OAuth access and refresh tokens at rest
DATABASE_URL The Postgres connection string. On Cloudflare, pooling comes from the Hyperdrive binding, but this is still required: survey access links are signed from it

There are deliberately only three, so a failure to start has a small blast radius.

Variable Default Purpose
PORT 3000 The port the server listens on
HOST 0.0.0.0 The interface it binds
NODE_ENV development Set to production on any real deployment
RELEASE_VERSION dev What this deployment calls itself, at GET /api/version and to every CLI that talks to it. dev reads as unknown and is never reported to a user
LOG_LEVEL info Log verbosity. Silent during tests regardless
DATABASE_URL_DIRECT A connection that bypasses a pooler. Set it when PgBouncer or an equivalent sits in front of Postgres

Read by the Docker Compose stack itself rather than by the server, so they do nothing on Kubernetes or Cloudflare.

Variable Default Purpose
SERVER_REPLICAS 3 How many server instances to run behind the load balancer
MINIO_CONSOLE_PORT 9001 Host port for the bundled object store’s console. Change it if something else on the host already uses 9001
POSTGRES_PASSWORD guidemode The bundled database’s password. Unused once DATABASE_URL is set

Each group is either fully configured or entirely absent. Half of one stops the server at boot, naming what is missing, rather than failing in a callback a week later.

Variable Notes
S3_BUCKET Presence of this turns the group on
S3_ENDPOINT Full origin, such as https://s3.eu-west-1.amazonaws.com or http://minio:9000
S3_ACCESS_KEY_ID
S3_SECRET_ACCESS_KEY
S3_REGION Optional. Defaults to auto
S3_ADDRESSING Optional, path or virtual-host. Guessed from the endpoint, and worth stating: MinIO uses path, AWS uses virtual-host, and the wrong choice returns an error that reads like a permissions problem

Without this group there is no transcript storage. Everything else still works.

Repository, issue and pull request sync.

Variable Notes
GITHUB_APP_ID Presence of this turns the group on
GITHUB_APP_PRIVATE_KEY
GITHUB_APP_WEBHOOK_SECRET Optional. Without it, webhooks are not accepted
GITHUB_APP_NAME Optional

Each is a pair, or a trio where a redirect URI is required.

Provider Variables
GitHub GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET
Google GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI
GitLab GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET, GITLAB_REDIRECT_URI
Microsoft MICROSOFT_CLIENT_ID, MICROSOFT_CLIENT_SECRET

Email sign-in works without any of these, provided RESEND_API_KEY is set.

Integration Variables
Jira JIRA_CLIENT_ID, JIRA_SECRET, JIRA_REDIRECT_URI
Linear LINEAR_CLIENT_ID, LINEAR_CLIENT_SECRET
Notion NOTION_CLIENT_ID, NOTION_CLIENT_SECRET
Slack SLACK_CLIENT_ID, SLACK_CLIENT_SECRET

Both are switched on by a flag rather than by a credential, so a deployment carrying price identifiers with billing off is read correctly as off.

Group Variables
Paddle PADDLE_ENABLED, PADDLE_API_KEY, PADDLE_WEBHOOK_SECRET, PADDLE_CLIENT_TOKEN, PADDLE_INDIVIDUAL_PRICE_ID, PADDLE_SMALL_TEAM_PRICE_ID, PADDLE_LARGE_TEAM_PRICE_ID, PADDLE_ENTERPRISE_PRICE_ID
Langfuse LANGFUSE_ENABLED, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, and optionally LANGFUSE_BASE_URL

Most self-hosted deployments leave billing off.

Variable Effect
RESEND_API_KEY Email. Without it, invitations and magic links are not sent
NOTION_WEBHOOK_SECRET Notion webhooks are rejected without it
SLACK_SIGNING_SECRET Verifies inbound Slack requests
GITHUB_PUBLIC_TOKEN Read-only token for the open-source benchmark corpus
ADMIN_SECRET Enables global administrator access

Session summaries, quality assessment and the agentic notebook.

Variable Notes
AI_PROVIDER Which provider to use by default
AI_MODELS Comma-separated model list, tried in order
GEMINI_API_KEY, OPENAI_API_KEY, CLAUDE_API_KEY Provider credentials
ANTHROPIC_API_KEY Used by the agentic notebook, separately from the above
AI_PROMPT_LOGGING Logs every prompt and response. Development only

Organizations can also configure their own provider and key in the product, which takes precedence over these.

Sensible on every deployment; worth tuning on a large one.

Variable Default Notes
JOBS_WORKER_ENABLED true Set false for a replica that serves traffic and never claims background work
JOBS_POLL_INTERVAL_MS 1000 How often a worker looks for work
JOBS_QUEUE_CONCURRENCY 2 Per replica, per queue
JOBS_WORKFLOW_CONCURRENCY 2 Per replica
JOBS_RETENTION_DAYS 7 How long finished job rows are kept
JOBS_SHUTDOWN_GRACE_MS 20000 How long a draining replica has to finish what it holds
Variable Notes
LOCAL_OBJECT_STORE_DIR Where transcripts are written when no S3 bucket is configured and this is not production. Refused in production, where a missing bucket means no transcript storage