Skip to content

Environment Variables


API (apps/api/)

These are read via NestJS ConfigService (config.get('VAR')) or directly via process.env['VAR']. The env schema is validated by Zod in apps/api/src/app.module.ts; validation logs loudly but does not abort, so tests and partial configs still boot. Optional services degrade gracefully rather than crashing — see the behaviour column.

Required

VariableExampleDescription
DATABASE_URLpostgresql://...:5433/regulusPrisma connection string (Docker Postgres on the VPS)
JWT_SECRET<random 64-char hex>HS256 signing secret for access + refresh tokens (min 20 chars)
NODE_ENVproductionControls dev-only behaviour (media sink, error details)

AI (both optional)

VariableRequired?Degradation when unset
ANTHROPIC_API_KEYoptionalAI reflection falls back to scripted questions + heuristic interest mapping
OPENAI_API_KEYoptionalEmbeddings disabled: semantic search / feed ranking no-op, discovery affinity section hidden

Real-time, email, federation

VariableRequired?Description / degradation
CENTRIFUGO_URLoptionalInternal Centrifugo HTTP API URL; unset → realtime publish skipped
CENTRIFUGO_API_KEYoptionalServer-to-server publish key
CENTRIFUGO_PUBLIC_URLoptionalPublic WS URL exposed to clients
CENTRIFUGO_HMAC_SECREToptionalConnection-token HMAC secret
RESEND_API_KEYoptionalResend key; unset → emails are logged only, not sent
EMAIL_FROMoptionalFrom address for transactional email
FEDERATION_HOSToptionalPublic host for ActivityPub actor URIs; unset → federation inert
APP_URLoptionalBase URL for email deep links
API_PUBLIC_URLoptionalExposed in CORS + link-preview allowlist
ALLOWED_ORIGINSoptionalComma-separated CORS origins
API_PORToptionalHTTP port (default 3001; prod binds 4101 behind nginx)

Storage (Cloudflare R2)

All optional — unset → media upload endpoints are disabled (dev uses a local sink when NODE_ENV !== production).

VariableExampleDescription
R2_ACCOUNT_IDabc123...Cloudflare account ID
R2_ACCESS_KEY_ID<key>R2 S3-compatible access key
R2_SECRET_ACCESS_KEY<secret>R2 secret
R2_BUCKETregulus-mediaMedia bucket name
R2_PUBLIC_HOSThttps://media.rgls.ukPublic CDN URL for committed assets

DB backups use a separate private R2 bucket configured in scripts/ops/backup-db.sh (not in the app's runtime env) — see Infrastructure.

Observability

VariableExampleDescription
SENTRY_DSNhttps://[email protected]/...Sentry error tracking
SENTRY_RELEASEv1.2.3Release identifier for source maps
SENTRY_TRACES_SAMPLE_RATE0.1Tracing sample rate (0..1)

Source maps: after pnpm --filter @regulus/api build, run pnpm --filter @regulus/api sentry:sourcemaps on deploy with SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT set in the environment. The release defaults to the current git SHA when SENTRY_RELEASE is unset — keep it identical to the runtime SENTRY_RELEASE so traces de-minify.


Mobile (apps/mobile/)

All variables must be prefixed with EXPO_PUBLIC_ to be embedded in the JS bundle. Set in .env.local or EAS secrets.

VariableExampleDescription
EXPO_PUBLIC_API_URLhttps://api.rgls.uk/api/v1Base URL for all API calls
EXPO_PUBLIC_POSTHOG_API_KEYphc_...PostHog analytics key
EXPO_PUBLIC_SENTRY_DSNhttps://[email protected]/...Sentry mobile DSN

Source maps: the @sentry/react-native/expo config plugin uploads maps during EAS builds. It activates only when SENTRY_ORG + SENTRY_PROJECT are set (see eas.json build profiles) and reads the auth token from the SENTRY_AUTH_TOKEN EAS secret: eas secret:create --scope project --name SENTRY_AUTH_TOKEN --value <token>.


Admin (apps/admin/)

No build-time env vars required. The admin panel resolves the API URL at runtime:

  • Dev: Vite proxy forwards /apilocalhost:3001 (configured in vite.config.ts).
  • Prod: Hardcoded https://api.rgls.uk in apps/admin/src/lib/api.ts.

To override the production API URL, edit PROD_API in apps/admin/src/lib/api.ts.

Optional documentation site URL (used by the Docs page):

VariableDefaultDescription
VITE_DOCS_URLhttps://docs.regulus.appVitePress docs site URL embedded in admin iframe
VITE_SENTRY_DSN(unset)Sentry DSN for the admin SPA. No-op when blank
VITE_SENTRY_RELEASE(unset)Optional release id surfaced to Sentry

Source maps: when SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT are present at build time, vite build auto-injects debug IDs and uploads maps via @sentry/vite-plugin. With any of them missing the build proceeds and simply skips the upload.


Local Development

Copy .env.example.env in apps/api/:

bash
cp apps/api/.env.example apps/api/.env
# Fill in DATABASE_URL and JWT_SECRET at minimum
pnpm dev

Minimum viable .env for local dev (no AI, no email, no real-time):

dotenv
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/regulus"
JWT_SECRET="dev-secret-change-in-production-use-64-random-hex-chars"
NODE_ENV="development"

With Anthropic AI and email:

dotenv
DATABASE_URL="postgresql://..."
JWT_SECRET="..."
NODE_ENV="development"
ANTHROPIC_API_KEY="sk-ant-..."
RESEND_API_KEY="re_..."
APP_URL="http://localhost:8081"

Regulus — invite-only social-knowledge platform