Environment Variables
All 55 environment variables for the Royal Glow platform — what they do, where they go, and how they're validated.
Environment Variables
Royal Glow runs a monorepo with three Next.js apps (apps/web, apps/admin, apps/cms) plus the apps/invoicing PDF render service, deployed across Cloudflare Workers (rgss-web, rgss-admin — via the OpenNext adapter @opennextjs/cloudflare), Render (rgss-cms), and Cloud Run (apps/invoicing), and relies on ~15 external services.
Environment variables are validated at build time using @t3-oss/env-nextjs + Zod. If any required variable is missing or malformed, the build fails immediately. Never use process.env directly — always import from apps/web/src/env.ts.
Guarded-no-op pattern. Optional integrations (Redis, R2, Resend, Brevo, web-push, Ably, Slack, QStash heartbeats) degrade gracefully. When their keys are absent the related call becomes a no-op + log instead of throwing: the health probe reports skip rather than fail, the Ably token route returns 503 so the client falls back to polling, and background jobs still complete and return 200. This is why the app builds and runs with an incomplete .env — only the truly required core (database, auth) is hard-validated.
Quick Start
Copy templates
cp apps/web/.env.example apps/web/.env.local
cp apps/admin/.env.example apps/admin/.env.local
cp apps/cms/.env.example apps/cms/.env.localFill in values
Populate each .env.local with values from your service dashboards.
Generate VAPID keys (one-time only)
bunx web-push generate-vapid-keysValidate
The build fails fast if anything required is missing or malformed.
cd apps/web && bun run buildFile Structure
Complete Variable Reference
Database (Neon)
Prop
Type
Per-environment branches: Use GitHub Environments so DATABASE_URL points to the correct Neon branch per environment (prod / pprd / test / dev).
Auth — Better Auth
Prop
Type
Email — Transactional (Resend)
Prop
Type
Email — Marketing (Brevo)
Prop
Type
Realtime — Ably
Prop
Type
File Storage — Cloudflare R2
Prop
Type
Cache — Upstash Redis
Prop
Type
Queue — Upstash QStash
Prop
Type
Web Push — VAPID Keys
Prop
Type
Generate once: bunx web-push generate-vapid-keys. These never change unless you intentionally rotate (which invalidates all existing push subscriptions).
Cloudflare — KV + CI/CD
Prop
Type
Observability — Sentry
Prop
Type
Observability — BetterStack
Prop
Type
Analytics — PostHog & Clarity
Prop
Type
Ads & Tracking — Meta
Prop
Type
Reporting
Prop
Type
CRM — AiSensy
Prop
Type
CMS — Payload
Prop
Type
App Configuration
Prop
Type
NODE_ENV vs APP_ENV: NODE_ENV is always development or production (Next.js convention). APP_ENV distinguishes between our 4 deployment environments: dev, test, pprd, prod. Use APP_ENV for environment-specific logic.
Variable Count Summary
| Category | Count |
|---|---|
| Database | 2 |
| Auth | 4 |
| Email (transactional + marketing) | 3 |
| Realtime (Ably) | 2 |
| File Storage (R2) | 5 |
| Cache (Redis) | 2 |
| Queue (QStash) | 3 |
| Web Push (VAPID) | 3 |
| Cloudflare KV + CI/CD | 3 |
| Sentry | 4 |
| BetterStack | 9 |
| Analytics | 3 |
| Meta Pixel + CAPI | 4 |
| Reporting | 2 |
| AiSensy | 2 |
| Payload | 1 |
| App Config | 3 |
| Total | 55 |
Platform Injection
| Platform | Where to set | Applied to |
|---|---|---|
| Cloudflare Workers | wrangler secret / Workers & Pages → Settings → Variables | apps/web + apps/admin (edge) |
| Render | Service → Environment tab | apps/cms (Payload CMS) |
| Cloud Run | Service → Variables & Secrets | apps/invoicing (PDF render) |
All platforms inject vars at runtime — no .env file is needed or present in production.
GitHub Secrets
Set under Repository Settings → Secrets and variables → Actions:
Reference in GitHub Actions:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL_PROD }}
BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}Was this page helpful?