Skip to content

Environment variables

The full annotated list lives in .env.example at the repo root. This page covers the ones you actually need to set.

For the full reference table organized by package, see Reference → Environment variables.

VariablePurpose
DATABASE_URLPostgres 16+ connection string
REDIS_URLRedis 7+ connection string
BETTER_AUTH_SECRET32+ chars; rotating it invalidates every session
ENCRYPTION_KEY32 hex chars; must match between api and worker
JOBS_HMAC_SECRETShared secret for HMAC-gated job admin endpoints
FRONTEND_URL / BACKEND_URLWhat the browser sees; powers CORS + cookies
S3_*Object storage (any S3-compatible store; MinIO locally, R2 / S3 / B2 / … in prod)
SCANI_CLOUD_URLWhere the data-provider lives (see Tier model)
SCANI_CLOUD_API_KEYBearer token the api + worker present to reach the data-provider

Each one unlocks specific functionality. The corresponding tRPC router returns a PRECONDITION_FAILED error at call-time if the key is unset — so unset keys fail loudly rather than silently misbehaving.

  • COINGECKO_API_KEY, FINNHUB_API_KEY
  • OPENAI_API_KEY — screenshot parsing
  • PERPLEXITY_API_KEY, DEEPSEEK_API_KEY — token-identity backfill
  • ETHERSCAN_API_KEY — EVM wallet balances (one key covers all EVM chains)
  • HELIUS_API_KEY — Solana balances
  • BINANCE_OAUTH_CLIENT_ID / _SECRET / _REDIRECT_URI — Binance exchange connection via OAuth
  • FASTMAIL_API_TOKEN — Fastmail JMAP delivery; or
  • SMTP_URL + SMTP_FROM — any SMTP server (Mailpit in dev, your provider in prod)

Two layers, with a strict ownership rule:

  • App-level (apps/*/src/config/env.ts) owns env vars that belong to the app itself — its bind port, its database connection, its frontend origin. Each app parses process.env once at boot via a zod schema and exits with a clear error listing every failing variable.
  • Package-level (packages/infra/<pkg>/src/config.ts) owns env vars that belong to that packageFASTMAIL_API_TOKEN for @scani/email, S3_* for @scani/storage, ENCRYPTION_KEY for @scani/security.

Apps that depend on a package do not redeclare that package’s env vars in their own schema — the package owns validation.

Every package config uses the same pattern: optional in dev/test, required in production. Production failures are non-recoverable misconfigurations; dev passthroughs let contributors boot without ceremony.