Configuration reference
All configuration is via environment variables, set in docker-compose.yml or your platform’s equivalent. The backend runs as either ./server (web) or ./server worker (background analytics). Which mode each variable applies to is noted per section.
See backend/.env.example for a copy-paste-ready template.
Core settings
Section titled “Core settings”Applies to: web server
| Variable | Default | Required | Description |
|---|---|---|---|
PORT |
8080 |
No | HTTP server port |
BACKEND_URL |
http://localhost:8080 |
No | Public URL of the backend; used for CLI device-code authorization flow |
FRONTEND_URL |
http://localhost:5173 |
Yes | Public URL of the frontend; used for OAuth redirects, email links, and CORS |
ALLOWED_ORIGINS |
http://localhost:5173 |
Yes | Comma-separated list of allowed CORS origins |
STATIC_FILES_DIR |
/app/static |
No | Directory for serving the built frontend |
CSRF_SECRET_KEY |
(none) | Yes | CSRF protection secret; must be at least 32 characters |
INSECURE_DEV_MODE |
false |
No | Set to true to disable secure-cookie requirements (local dev without HTTPS) |
TRUSTED_PROXY_HEADERS |
(all) | No | Comma-separated list of proxy header names to honor for client-IP extraction (e.g. Fly-Client-IP,CF-Connecting-IP). When unset, all known proxy headers are trusted. Set this to only the header your edge proxy sets so attackers can’t spoof other headers to bypass IP rate limits. |
Database
Section titled “Database”Applies to: web server and worker
| Variable | Default | Required | Description |
|---|---|---|---|
DATABASE_URL |
(none) | Yes | PostgreSQL connection string (e.g. postgres://user:pass@host:5432/confab?sslmode=disable) |
MIGRATE_DATABASE_URL |
Falls back to DATABASE_URL |
No | Separate connection string for running migrations with an elevated database user |
Storage
Section titled “Storage”Applies to: web server and worker
| Variable | Default | Required | Description |
|---|---|---|---|
S3_ENDPOINT |
(none) | Yes | S3/MinIO endpoint (e.g. localhost:9000) |
AWS_ACCESS_KEY_ID |
(none) | Yes | S3/MinIO access key |
AWS_SECRET_ACCESS_KEY |
(none) | Yes | S3/MinIO secret key |
BUCKET_NAME |
(none) | Yes | S3/MinIO bucket name |
S3_USE_SSL |
true |
No | Use SSL for S3 connections; set to false for local MinIO |
Authentication
Section titled “Authentication”Applies to: web server
At least one method must be enabled. All four can be used simultaneously.
Password auth
Section titled “Password auth”Recommended for self-hosted deployments.
| Variable | Default | Required | Description |
|---|---|---|---|
AUTH_PASSWORD_ENABLED |
false |
No | Set to true to enable username/password login |
ADMIN_BOOTSTRAP_EMAIL |
(none) | If password auth enabled | Email for the initial admin user (created on first startup if no users exist) |
ADMIN_BOOTSTRAP_PASSWORD |
(none) | If password auth enabled | Password for the initial admin user; remove after setup |
GitHub OAuth
Section titled “GitHub OAuth”Create an OAuth app at github.com/settings/developers.
| Variable | Default | Required | Description |
|---|---|---|---|
GITHUB_CLIENT_ID |
(none) | If GitHub OAuth enabled | GitHub OAuth app client ID |
GITHUB_CLIENT_SECRET |
(none) | If GitHub OAuth enabled | GitHub OAuth app client secret |
GITHUB_REDIRECT_URL |
(none) | If GitHub OAuth enabled | OAuth callback URL (e.g. https://your-domain/auth/github/callback) |
Google OAuth
Section titled “Google OAuth”Create OAuth credentials at console.cloud.google.com/apis/credentials.
| Variable | Default | Required | Description |
|---|---|---|---|
GOOGLE_CLIENT_ID |
(none) | If Google OAuth enabled | Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
(none) | If Google OAuth enabled | Google OAuth client secret |
GOOGLE_REDIRECT_URL |
(none) | If Google OAuth enabled | OAuth callback URL (e.g. https://your-domain/auth/google/callback) |
Generic OIDC
Section titled “Generic OIDC”Works with Okta, Auth0, Azure AD, Keycloak, etc. All four variables must be set.
| Variable | Default | Required | Description |
|---|---|---|---|
OIDC_ISSUER_URL |
(none) | If OIDC enabled | OIDC issuer URL (e.g. https://dev-12345.okta.com) |
OIDC_CLIENT_ID |
(none) | If OIDC enabled | OIDC client ID |
OIDC_CLIENT_SECRET |
(none) | If OIDC enabled | OIDC client secret |
OIDC_REDIRECT_URL |
(none) | If OIDC enabled | OAuth callback URL (e.g. https://your-domain/auth/oidc/callback) |
OIDC_DISPLAY_NAME |
SSO |
No | Controls the login button text (“Continue with …”) |
Shared auth settings
Section titled “Shared auth settings”| Variable | Default | Required | Description |
|---|---|---|---|
ALLOWED_EMAIL_DOMAINS |
(all domains) | No | Comma-separated list of allowed email domains; applies to all auth methods |
OAUTH_AUTO_LINK_EMAIL |
false |
No | When true, a first-time OAuth login whose email matches an existing account (password or another provider) is automatically linked to it. Default false rejects the login (/login?error=account_exists) instead, preventing account takeover via an attacker-controlled IdP email. Only enable if you trust every configured IdP to strictly verify email ownership. Returning users and brand-new emails are unaffected. |
Demo mode
Section titled “Demo mode”| Variable | Default | Required | Description |
|---|---|---|---|
DEMO_IDENTITY_EMAIL |
(none) | No | When set, designates a single user as the read-only demo identity. On startup the named user is provisioned with read_only=true, name "Demo", is_admin=false, and any password identity is stripped (login disabled). Anonymous web visitors on auth-required routes are auto-impersonated as the demo identity via a single shared session cookie (HMAC-derived from CSRF_SECRET_KEY). Mutating requests from the demo identity return 403 {"error":"read_only_user", ...}. The login handler and all OAuth callbacks reject this email. Real users (with their own password / OAuth) continue to authenticate and write normally. Unset = zero behavior change anywhere — safe to leave off in regular deployments. |
See Demo mode for a deeper guide.
Applies to: web server
Email is enabled when both RESEND_API_KEY and EMAIL_FROM_ADDRESS are set.
| Variable | Default | Required | Description |
|---|---|---|---|
RESEND_API_KEY |
(none) | If email enabled | Resend API key (resend.com) |
EMAIL_FROM_ADDRESS |
(none) | If email enabled | Sender email address |
EMAIL_FROM_NAME |
Confab |
No | Sender display name |
EMAIL_RATE_LIMIT_PER_HOUR |
100 |
No | Per-user email rate limit |
SUPPORT_EMAIL |
(none) | No | Support email shown in UI |
Smart recaps
Section titled “Smart recaps”Applies to: web server and worker
AI-powered session summaries, generated by Anthropic or OpenAI. Requires an Anthropic API key or an OpenAI API key for the selected provider.
| Variable | Default | Required | Description |
|---|---|---|---|
SMART_RECAP_ENABLED |
false |
No | Set to true to enable smart recaps |
SMART_RECAP_LLM_PROVIDER |
anthropic |
No | LLM provider for recap generation: anthropic or openai. Any other value fails startup, even when smart recaps are disabled. |
ANTHROPIC_API_KEY |
(none) | If provider is anthropic |
Anthropic API key |
OPENAI_API_KEY |
(none) | If provider is openai |
OpenAI API key |
SMART_RECAP_MODEL |
(none) | If smart recaps enabled | Model for the selected provider (e.g. claude-haiku-4-5-20251001 or gpt-5.6-luna) |
SMART_RECAP_QUOTA_LIMIT |
0 (unlimited) |
No | Per-user monthly generation cap. Positive integer enforces a limit; 0 or omitted means unlimited. |
SMART_RECAP_MAX_OUTPUT_TOKENS |
1000 |
No | Maximum LLM output tokens per recap |
SMART_RECAP_MAX_TRANSCRIPT_TOKENS |
50000 |
No | Maximum input tokens per transcript (~chars/4) |
If SMART_RECAP_ENABLED=true but the selected provider’s API key or SMART_RECAP_MODEL is missing, smart recaps stay disabled and the server and worker log a startup warning naming the missing variable. Switching providers does not regenerate existing recaps.
With the anthropic provider, smart recaps use structured outputs with extended thinking disabled. Supported models are Claude Haiku 4.5, Sonnet 5, Opus 4.8, and Opus 5. Fable and Mythos models (thinking always on) are not supported for smart recaps.
Admin & user management
Section titled “Admin & user management”Applies to: web server
| Variable | Default | Required | Description |
|---|---|---|---|
SUPER_ADMIN_EMAILS |
(none) | No | Comma-separated email addresses with admin panel access. Admin authorization is the union of this list and the per-user is_admin column (5k4v) — env super-admins are always admins (recovery path); other admins can be granted/revoked at runtime from the admin UI without an env edit + restart. Validated at startup: malformed/duplicate entries are logged as warnings and the normalized list is logged. Keep any demo identity’s email out of this list. |
MAX_USERS |
50 |
No | Maximum number of registered users; set to 0 to block new registrations |
SESSION_IDLE_TIMEOUT |
48h |
No | Sliding idle timeout for web sessions (time.ParseDuration format, e.g. 48h, 30m). A session inactive longer than this is rejected even within the 7-day absolute cap. Invalid/empty/non-positive values fall back to the default. |
Instance customization
Section titled “Instance customization”Applies to: web server
Sharing behavior and UI customization.
| Variable | Default | Required | Description |
|---|---|---|---|
SHARE_ALL_SESSIONS_TO_AUTHENTICATED |
false |
No | Make every session visible to every authenticated user; useful for small teams that want full transparency |
ENABLE_SHARE_CREATION |
false |
No | Enable share link creation |
SHARE_DAILY_QUOTA |
100 |
No | Per-user cap on shares created in a rolling 24h window; the creation endpoint returns 429 once a user exceeds it. Set to 0 to disable the cap. |
ENABLE_ORG_ANALYTICS |
false |
No | Enable the Organization Analytics view — per-user aggregated cost and usage across the whole org. Every authenticated user can see every other user’s totals, so only enable for trusted-team deployments. |
ENABLE_SAAS_FOOTER |
false |
No | Show the SaaS footer (GitHub, Discord, Help links, copyright); off by default for self-hosted |
ENABLE_SAAS_TERMLY |
false |
No | Enable the Termly cookie-consent banner (SaaS only); off by default for self-hosted |
DISABLE_UPDATE_CHECK |
false |
No | Suppress the in-product “Update available” badge (skips the periodic GitHub release check). Useful for air-gapped deployments. Implicitly true when ENABLE_SAAS_FOOTER=true, since SaaS users can’t self-upgrade. |
Model pricing
Section titled “Model pricing”Applies to: web server, worker
Model token prices are no longer baked into the build — the backend pulls the latest price table from confabulous.dev so a self-hosted instance picks up new prices (and new models within an existing provider) without a redeploy. The fetch is best-effort: if the source is unreachable, invalid, or older than the build’s embedded table, the embedded table is used. The managed instance auto-disables this (it is the source).
| Variable | Default | Required | Description |
|---|---|---|---|
PRICING_SOURCE_URL |
https://confabulous.dev/api/v1/pricing |
No | Where to pull the latest model price table from. Set to empty (PRICING_SOURCE_URL=) to disable fetching and use the embedded table only (air-gapped deployments). |
PRICING_REFRESH_INTERVAL |
2h |
No | How often to refresh the price table (Go duration, e.g. 2h, 90m). Failures are retried after 15 minutes. |
Worker
Section titled “Worker”Applies to: worker only
Precomputes analytics and smart recaps in the background.
| Variable | Default | Required | Description |
|---|---|---|---|
WORKER_POLL_INTERVAL |
30m |
No | How often to check for stale sessions |
WORKER_MAX_SESSIONS |
20 |
No | Maximum sessions to process per cycle |
WORKER_MAX_SEARCH_INDEX_SESSIONS |
200 |
No | Maximum sessions to (re)build the search index for per cycle (search indexing is cheap, so this is higher than WORKER_MAX_SESSIONS) |
WORKER_DRY_RUN |
false |
No | Log what would be done without actually processing |
Staleness thresholds (advanced)
Section titled “Staleness thresholds (advanced)”Controls when sessions need recomputation. WORKER_REGULAR_* = analytics cards, WORKER_RECAP_* = smart recaps.
| Variable | Default | Description |
|---|---|---|
WORKER_REGULAR_THRESHOLD_PCT |
0.20 |
Percentage change (0–1) to trigger analytics recompute |
WORKER_REGULAR_BASE_MIN_LINES |
5 |
Minimum new lines before recompute |
WORKER_REGULAR_BASE_MIN_TIME |
3m |
Minimum age of new data |
WORKER_REGULAR_MIN_INITIAL_LINES |
10 |
Minimum lines for first computation |
WORKER_REGULAR_MIN_SESSION_AGE |
10m |
Minimum session age |
WORKER_RECAP_THRESHOLD_PCT |
0.20 |
Percentage change (0–1) to trigger recap recompute |
WORKER_RECAP_BASE_MIN_LINES |
150 |
Minimum new lines before recompute |
WORKER_RECAP_BASE_MIN_TIME |
30m |
Minimum age of new data |
WORKER_RECAP_MIN_INITIAL_LINES |
25 |
Minimum lines for first computation |
WORKER_RECAP_MIN_SESSION_AGE |
10m |
Minimum session age |
Observability
Section titled “Observability”Applies to: web server and worker
| Variable | Default | Required | Description |
|---|---|---|---|
LOG_LEVEL |
info |
No | Log level: debug, info, warn, error |
ENABLE_PPROF |
false |
No | Enable pprof profiling server on localhost:6060 |
HTTP tuning
Section titled “HTTP tuning”Applies to: web server
| Variable | Default | Required | Description |
|---|---|---|---|
HTTP_READ_TIMEOUT |
30s |
No | HTTP read timeout |
HTTP_WRITE_TIMEOUT |
30s |
No | HTTP write timeout |