Skip to content

Configuration

The backend reads settings from environment variables prefixed STEPT_ (or a .env file in backend/). Unknown variables are ignored.

VariableDefaultPurpose
STEPT_ENVdevdev | test | prod — prod enables the boot guardrails
STEPT_SECRET_KEYdev-secret-key-change-meSigns all JWTs and derives the encryption key (see warning below)
STEPT_BACKEND_PORT8600API port
STEPT_PUBLIC_BASE_URLhttp://localhost:8600Public API origin — widget snippet src, OAuth redirect URIs
STEPT_APP_BASE_URLhttp://localhost:5273Dashboard origin — CORS allow-list seed, links in emails
STEPT_CORS_ORIGINS[]Extra allowed origins for the dashboard API
STEPT_EXTENSION_WEB_STORE_URLemptyChrome Web Store link shown for the recorder extension
VariableDefaultPurpose
STEPT_DATABASE_URLsqlite+aiosqlite:///./stept.dbUse postgresql+asyncpg://… in production (pgvector)
STEPT_REDIS_URLunsetEnables the ARQ worker queue, Redis rate limits and pub/sub. Unset = in-process fallbacks (single node only)
STEPT_DB_POOL_SIZE10Connection pool size. Read from the process environment only — unlike every other row, an entry in backend/.env is ignored
STEPT_STORAGE_DIR./data/uploadsAttachment/upload storage path
STEPT_MAX_UPLOAD_MB25Upload size cap
VariableDefaultPurpose
STEPT_ALLOW_SIGNUPtrueSet false to make an internet-facing instance invite-only — signup is closed, members join via invitation
STEPT_ACCESS_TOKEN_TTL_MINUTES15Access-token lifetime
STEPT_REFRESH_TOKEN_TTL_DAYS30Refresh-cookie lifetime (rotating, reuse-detected)
STEPT_REFRESH_ROTATION_GRACE_SECONDS60Window in which a just-rotated refresh token is still accepted (parallel tabs racing the rotation)
STEPT_INVITATION_TTL_DAYS7Member invitation validity
STEPT_RATE_LIMIT_ENABLEDtrueToggle for the abuse rate limits
STEPT_MCP_RATE_LIMIT_PER_MINUTE120Per-key rate limit on the MCP server; 0 disables
STEPT_TRUSTED_PROXY_HOPS0How many X-Forwarded-For hops to trust (e.g. 2 behind Cloudflare + Caddy)
STEPT_EXPOSE_API_DOCSunsetOpenAPI/Swagger at /api/v1/docs — on unless env=prod; set to force either way
VariableDefaultPurpose
STEPT_SMTP_HOSTunsetUnset = transactional email is logged to the API console instead of sent — including the invite/reset links, so you can copy one out of the logs (invites, password resets)
STEPT_SMTP_PORT25
STEPT_SMTP_USER / STEPT_SMTP_PASSWORDunset
STEPT_SMTP_TLSfalse
STEPT_EMAIL_FROMStept <[email protected]>From header
STEPT_INBOUND_EMAIL_DOMAINunsetEnables auto-generated in-{hex}@{domain} forwarding addresses on email inboxes

Per-inbox email transports (SES, Resend, Postmark, SendGrid, Mailgun, per-inbox SMTP, Gmail/Microsoft OAuth) are configured per inbox in the dashboard, not via env vars.

Integration credentials (instance-level OAuth apps)

Section titled “Integration credentials (instance-level OAuth apps)”
VariablePurpose
STEPT_GOOGLE_CLIENT_ID / STEPT_GOOGLE_CLIENT_SECRETGmail + Google Drive
STEPT_MICROSOFT_CLIENT_ID / STEPT_MICROSOFT_CLIENT_SECRETMicrosoft 365
STEPT_SLACK_CLIENT_ID / STEPT_SLACK_CLIENT_SECRET / STEPT_SLACK_SIGNING_SECRETSlack
STEPT_NOTION_CLIENT_ID / STEPT_NOTION_CLIENT_SECRETNotion
STEPT_CONFLUENCE_CLIENT_ID / STEPT_CONFLUENCE_CLIENT_SECRETConfluence
STEPT_GITHUB_CLIENT_ID / STEPT_GITHUB_CLIENT_SECRETGitHub — the repo knowledge connector and “Sign in with GitHub”
STEPT_GOOGLE_LOGIN_CLIENT_ID / STEPT_GOOGLE_LOGIN_CLIENT_SECRETA separate OAuth app for “Sign in with Google”; unset, login falls back to the integrations Google app above
STEPT_OAUTH_BASE_OVERRIDEDev/test only: redirect OAuth endpoints at a stub

Workspaces can override any of these with their own OAuth app in the dashboard — the workspace credential always wins. AI provider keys (OpenAI, Anthropic, …) are not env vars: each workspace adds them in the dashboard, encrypted at rest.

All unset (the default) = billing is off and every feature is entitled — the normal state for a self-hosted instance.

VariablePurpose
STEPT_STRIPE_SECRET_KEYStripe API key
STEPT_STRIPE_WEBHOOK_SECRETVerifies POST /api/stripe/webhook
STEPT_STRIPE_PUBLISHABLE_KEYUsed by the dashboard’s checkout flow
STEPT_STRIPE_PRICE_CLOUD / STEPT_STRIPE_PRICE_BUSINESSPrice ids for the two paid plans
VariableDefaultPurpose
STEPT_EMBEDDING_DIM384Vector dimension of the local fallback embedder
STEPT_CRAWL_USER_AGENTSteptBot/1.0 (+https://stepped.ai)User-Agent for website crawls — self-hosters should set their own so site owners can tell whose bot it is
STEPT_CRAWL_PROXY_URLunsetRoute crawler HTTP through a proxy
VariableDefaultPurpose
STEPT_SCHEDULER_ENABLEDtruePeriodic jobs (SLA scans, scheduled syncs). In the compose stack it runs in a dedicated single-replica scheduler container and is disabled on api
STEPT_SCHEDULER_TICK_SECONDS15Scheduler tick interval
STEPT_WEB_CONCURRENCY4 (deploy)uvicorn worker count (read by the container entrypoint)
STEPT_API_KEYunsetMCP stdio mode only — the client credential; never authenticates HTTP

STEPT_SECRET_KEY is load-bearing twice: it signs every JWT (sessions, widget tokens, password resets, extension tokens, OAuth state) and the encryption key for stored secrets — AI provider keys, channel credentials, OAuth tokens — is derived from it. Rotating it invalidates all stored credentials, which then need re-entering. Generate a strong one once: python -c 'import secrets; print(secrets.token_urlsafe(48))'.

With STEPT_ENV=prod the app refuses to boot if the secret key is a known default or shorter than 32 characters, or if either base URL is non-localhost http://. Database schema comes from migrations in prod — the container entrypoint runs alembic upgrade head on API start; auto table creation only runs in dev.