The backend is configured entirely through environment variables, loaded at
startup with kelseyhightower/envconfig
(see internal/config). This page is the canonical reference for every variable.
The authoritative source is backend/.env.example in the
repo — copy it to backend/.env for local
development (make backend-run-dev does this automatically if .env is missing).
Values come from the process environment. There is no config file format; in
local dev the Makefile exports the contents of backend/.env.
Variables are read once at boot. Most are optional and have safe defaults;
optional integrations stub out cleanly when left empty.
A handful are hard requirements — the service fails to start without them.
Hard requirements
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME — a reachable Postgres.
ENCRYPTION_KEY — must be exactly 32 bytes (AES-256). The service refuses
to start otherwise. Generate one with openssl rand -hex 16 (32 hex chars = 32 bytes).
Variable Default Required Purpose PORT8080No HTTP listen port. LOG_LEVELinfoNo debug | info | warn | error. Use debug locally.LOG_FORMATjsonNo json (structured, for aggregators) or text (human-readable).SERVICE_VERSIONdevNo Version tag attached to metrics/traces.
Variable Default Required Purpose DB_HOSTlocalhostYes Postgres host. Use postgres with Docker Compose. DB_PORT5432Yes Postgres port. DB_USERvibexp_appYes Database user. DB_PASSWORDlocal_passwordYes Database password. Change for any real deployment. DB_NAMEvibexp_ioYes Database name.
See Database & Migrations for pooling and
migration behaviour.
Variable Default Required Purpose ENCRYPTION_KEY— Yes AES-256 key for encrypting sensitive data at rest. Must be exactly 32 bytes. API_KEY_COMMON— No Shared API key for the common API surface. BACKOFFICE_ADMIN_API_KEY— No Admin key for back-office endpoints (/bo/*). Separate from JWTs and regular API keys.
Selects and configures the web-login identity provider. See
Authentication for the full model.
Variable Default Required Purpose AUTH_PROVIDER(empty) No workos, oidc, or empty (auto-detect: WorkOS if its credentials are set, else a no-op stub).SIGNIN_ALLOWED_EMAILS(empty) No Comma-separated allowlist. Empty means open registration. DEV_LOGIN_ENABLEDfalseNo Enables /api/v1/auth/dev/login (bypasses the IdP). Local development only.
Caution
Misconfiguration is never fatal: if the selected provider can’t initialize (e.g.
OIDC discovery fails against a bad issuer), the backend logs a warning, falls
back to the no-op stub, and still boots. Web login is disabled, but dev login
keeps working.
Variable Default Required Purpose WORKOS_API_KEY(empty) When using WorkOS WorkOS API key. WORKOS_CLIENT_ID(empty) When using WorkOS WorkOS Client ID. WORKOS_COOKIE_PASSWORDdev value When using WorkOS 32-byte hex string deriving the AES-GCM key that encrypts the vx_session cookie. Generate with openssl rand -hex 32. WORKOS_REDIRECT_URIhttp://localhost:8080/api/v1/auth/callbackWhen using WorkOS OAuth callback registered in WorkOS.
Works with any OIDC-compliant issuer (Keycloak, Authentik, Zitadel, Auth0, Google).
Variable Default Required Purpose OIDC_ISSUER_URL(empty) When using OIDC Issuer for discovery (/.well-known/openid-configuration appended). OIDC_CLIENT_ID(empty) When using OIDC OAuth client ID. OIDC_CLIENT_SECRET(empty) When using OIDC OAuth client secret. OIDC_REDIRECT_URIhttp://localhost:8080/api/v1/auth/callbackWhen using OIDC Callback URI registered with the provider.
The /mcp/v1/common endpoint is an OAuth 2.1 resource server delegating to
AuthKit. See MCP Server .
Variable Default Required Purpose MCP_OAUTH_ISSUER(empty) To enable MCP AuthKit issuer URL. JWKS fetched from <issuer>/oauth2/jwks. Empty disables the endpoint (rejects all tokens with 401). MCP_RESOURCE_URI(empty) To enable MCP Canonical MCP resource identifier and required token audience (RFC 8707). No default.
When set, /api/v1/* accepts AuthKit bearer JWTs (mobile / native PKCE clients)
alongside session cookies and API keys.
Variable Default Required Purpose API_OAUTH_ISSUER(empty) No AuthKit issuer URL. Empty rejects non-API-key bearer tokens with 401. API_OAUTH_AUDIENCES(empty) No Optional comma-separated aud allow-list. Default accepts any audience except the MCP resource URI.
Variable Default Required Purpose FRONTEND_BASE_URLhttp://localhost:5173No Public URL of the web app (redirects, email links). CORS_ALLOWED_ORIGINS(empty) No Comma-separated allowed origins. Empty allows only localhost dev origins.
Variable Default Required Purpose GCS_RESOURCE_ATTACHMENTS_BUCKET(empty) No GCS bucket for attachments. Empty disables attachments (upload/download/delete return 503).
Embeddings are generated in-process by an async event-bus worker: text is chunked
in Go, embedded via the active provider, and stored in pgvector. There is no
external AI service and no message broker.
Variable Default Required Purpose EMBEDDING_MODELgemini-embedding-001No The model_id tag written on every row and used as the search filter. Set to the model your provider serves. EMBEDDING_CHUNK_SIZE1000No Rune-based chunk size for the in-Go chunker. EMBEDDING_CHUNK_OVERLAP200No Overlap between chunks (must be smaller than the chunk size).
Note
The embedding provider (an OpenAI-compatible /v1/embeddings endpoint:
OpenAI, Ollama, LocalAI, vLLM, TEI, …) is configured in-app in the
embedding_providers table (base_url, api_key, provider_type), not via env.
If no provider is configured, entities are still saved and embedding is skipped.
The embedding vector width is fixed at 1024 in code — it is locked to the
pgvector column and is not configurable. There is no EMBEDDING_DIMENSIONS
variable. Pick a model that outputs (or can be asked for) 1024 dimensions.
Variable Default Required Purpose EMAIL_PROVIDERsmtpNo smtp, mailgun, postmark, or sendgrid.EMAIL_FROM_ADDRESSdev@vibexp.localRequired for non-smtp providers Sender address. Falls back to SMTP_USERNAME for smtp. CONTACT_RECIPIENT_ADDRESS(empty) No Inbox for contact/support emails. Falls back to EMAIL_FROM_ADDRESS, then SMTP_USERNAME.
SMTP (EMAIL_PROVIDER=smtp). Dev defaults point at Mailpit (UI at
http://localhost:8025).
Variable Default Purpose SMTP_HOSTlocalhostSMTP host. SMTP_PORT1025SMTP port. SMTP_USERNAMEdevSMTP username. SMTP_PASSWORDdevSMTP password.
Mailgun (EMAIL_PROVIDER=mailgun).
Variable Default Purpose MAILGUN_DOMAINmg.example.comMailgun sending domain. MAILGUN_SENDING_KEY— Mailgun private API key. MAILGUN_BASE_URL(empty) Region base URL; empty uses the US default.
Postmark (EMAIL_PROVIDER=postmark).
Variable Default Purpose POSTMARK_SERVER_TOKEN— Postmark Server API token. POSTMARK_MESSAGE_STREAMoutboundMessage stream to send on.
SendGrid (EMAIL_PROVIDER=sendgrid).
Variable Default Purpose SENDGRID_API_KEY— SendGrid API key with the “Mail Send” permission.
Optional. Leave empty for local dev (the provider stubs out).
Variable Default Required Purpose GITHUB_APP_ID(empty) No App ID from your GitHub App settings. GITHUB_APP_PRIVATE_KEY(empty) No Base64-encoded private key. A non-empty but invalid value fails startup on PEM parsing. GITHUB_CLIENT_ID(empty) No OAuth Client ID for user authorization. GITHUB_CLIENT_SECRET(empty) No OAuth Client Secret. GITHUB_WEBHOOK_URLhttps://api.example.com/webhooks/githubNo Public URL GitHub sends events to. GITHUB_WEBHOOK_SECRET(empty) No Secret used to verify webhook payloads.
Variable Default Required Purpose HUBSPOT_CRM_ACCESS_KEY(empty) No HubSpot Private App access token for contact sync. Empty disables the integration.
Async event processing (embeddings, analytics, HubSpot sync). All optional with
production-tuned defaults; values are validated and capped.
Variable Default Max Purpose EVENT_BUS_WORKER_COUNT201000Concurrent event workers. EVENT_BUS_BUFFER_SIZE50010000Event queue buffer size. EVENT_BUS_MAX_RETRIES310Max retry attempts per event. EVENT_BUS_RETRY_BACKOFF200ms5sBase retry delay; exponential, capped at 30s per attempt. EVENT_BUS_RETRY_JITTERtrue— Randomize backoff (±10%) to avoid thundering herd.
Variable Default Required Purpose OTEL_EXPORTER_OTLP_ENDPOINTlocalhost:4317No OTLP collector endpoint (gRPC host:port, no scheme). OTEL_METRIC_EXPORT_INTERVAL60sNo Metric export interval. OTEL_ENVIRONMENT(empty) No Deployment environment (e.g. development, production). Takes precedence over ENVIRONMENT/ENV/DEPLOYMENT_ENVIRONMENT. Defaults to production if none set. GCP_PROJECT_ID(empty) No Used only for observability (trace/log correlation).
Variable Default Required Purpose A2A_DEFAULT_TIMEOUT5mNo Max time to wait for agent-to-agent HTTP responses.
Abuse-hardening backstops; all have safe defaults.
Variable Default Purpose MAX_BODY_SIZE_BYTES10485760 (10 MiB)Global request-body cap. Contact form and webhooks cap at 64 KiB. AUTH_RATE_LIMIT_PER_MINUTE10Per-IP limit on /api/v1/auth/*. CONTACT_RATE_LIMIT_PER_MINUTE5Per-IP limit on the contact form. API_RATE_LIMIT_PER_MINUTE100Per-IP limit on the authenticated API surface.
Variable Default Purpose ERROR_TYPE_BASE_URIabout:blankRFC 9457 error type base URI. Set to a public URL documenting your error codes (joined as <base>/<code>).
OIDC auth for internal job endpoints (/internal/jobs/*), e.g. Cloud Scheduler.
Unrelated to embeddings; leave empty for local dev.
Variable Default Purpose PUBSUB_PUSH_AUDIENCE(empty) Public HTTPS URL the OIDC caller targets; the token’s audience must match it. PUBSUB_PUSH_SERVICE_ACCOUNT_SUFFIX(empty) Optional. Restrict accepted tokens to a service-account domain.