Environment Variables
Every environment variable thunder-core reads, plus database-backed env vars resolved at runtime.
thunder-core reads the variables below. Set them in .env, or store them at runtime in the envs collection (see Database-backed Env Vars).
The authoritative list is whatever the code reads. If in doubt, grep for Env.get / Env.list / Env.number / Env.enabled / Env.params across lib/, utils/, routes/, and hooks/.
Required
BASE_URL=http://localhost:8000 # Public base URL; used by better-auth & the OAuth2 issuer
SECRET_KEY=<random-strong-secret> # Signing secret for sessions and OAuth2 JWTs
BETTER_AUTH_CAPABILITIES=email,signup # Comma list enabling auth features (see below)BETTER_AUTH_CAPABILITIES toggles auth features (see lib/auth.ts):
| Capability | Effect |
|---|---|
signup | Allow new user creation |
email | Enable email + password auth |
magicLink | Enable magic-link sign up / sign in |
github | Enable the GitHub social provider (requires GITHUB_* vars) |
google | Enable the Google social provider (requires GOOGLE_* vars) |
facebook | Enable the Facebook social provider (requires FACEBOOK_* vars) |
multiSession | Allow multiple concurrent sessions per user |
Auth / Session (optional)
BETTER_AUTH_TRUSTED_ORIGIN=http://localhost:3000 # Comma list of trusted origins
BETTER_AUTH_TRUST_DEVICE_DAYS=30 # 2FA trust-device window (default 30)
BETTER_AUTH_MAX_MULTI_SESSIONS=5 # Max sessions when multiSession is enabled (default 5)
BETTER_AUTH_SAME_SITE=Lax # Overrides the session cookie SameSite attribute
GITHUB_CLIENT_ID=... # Required only if the "github" capability is on
GITHUB_CLIENT_SECRET=...
GOOGLE_CLIENT_ID=... # Required only if the "google" capability is on
GOOGLE_CLIENT_SECRET=...
FACEBOOK_CLIENT_ID=... # Required only if the "facebook" capability is on
FACEBOOK_CLIENT_SECRET=...Cookie defaults come from lib/auth.ts:
| Attribute | Default |
|---|---|
sameSite | BETTER_AUTH_SAME_SITE if set, otherwise Strict in production and Lax elsewhere |
secure, httpOnly | enabled in production only |
Branding
Served by the auth branding endpoint:
APP_DISPLAY_NAME=My App # Optional; falls back to "Thunder"
APP_DESCRIPTION=... # Optional
APP_LOGO=https://.../logo.png # Optional
APP_HOMEPAGE_URL=https://... # Optional
APP_TERMS_URL=https://... # Optional
APP_PRIVACY_URL=https://... # Optional
APP_THEME=primary:#000&bg:#fff # Parsed via Env.params() into a key/value record
APP_HIDE_POWERED_BY=true # Hides the "powered by" label in the auth UIEvery branding variable is optional - the endpoint returns name: "Thunder" when APP_DISPLAY_NAME is unset. See routes/auth.ts.
Email (SMTP)
Used by the Mailer:
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USERNAME=...
SMTP_PASSWORD=...
SMTP_SENDER=no-reply@example.com
SMTP_SENDER_NAME=My App
SMTP_DEBUG=false # Enables nodemailer debug outputImageKit
IMAGEKIT_PRIVATE_KEY=private_...
IMAGEKIT_PUBLIC_KEY=public_...Wallet / Currencies
Used by the wallet metadata endpoint:
DEFAULT_CURRENCY=pkr # Default wallet currency (defaults to "pkr")
AVAILABLE_CURRENCIES=pkr,usd,eur # Comma list surfaced by the wallet metadata endpointRBAC Behavior
RBAC_NO_CASCADE=false # If true, a tenant member's role does NOT cascade from the parent inviterDatabase-backed Env Vars
The essentials hook (hooks/essentials.ts) installs Env.onGetFailed, so any env var not found in the process environment is looked up in the envs MongoDB collection ({ key, value }).
This lets you manage secrets/config at runtime through the envs CRUD route instead of redeploying. The same hook also handles CORS (preflight + response headers, and allows the X-TENANT-ID header).
Because of this fallback, you can ship with only DATABASE_URL and SECRET_KEY in .env and store the rest in the database - useful for rotating secrets without a redeploy.