Environment Variables
Start with the required boot values, then enable provider, operational, and testing groups only when the corresponding capability is used.
On this page
Environment inventory
The names below mirror the application env template. Keep browser-safe values public and every provider or service credential server-only.
| Group | Requirement | Variables | Purpose |
|---|---|---|---|
| Supabase core | Required | NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY, STATIC_DATA_MODE | Browser auth, request-scoped database access, and trusted server operations. |
| Site identity and first admin | Required for launch | APP_ENV, APP_URL, DEPLOYMENT_PLATFORM, NEXT_PUBLIC_SITE_NAME, NEXT_PUBLIC_SUPPORT_EMAIL, SUPER_ADMIN_EMAIL | Canonical URLs, public identity, support contact, and initial super-admin assignment. |
| Localization bootstrap | Optional | APP_DEFAULT_LOCALE, APP_DEFAULT_TIMEZONE, APP_DEFAULT_CURRENCY | Seeds and recovers locale, timezone, and currency values when database settings are missing. |
| Analytics | Optional | NEXT_PUBLIC_GA_MEASUREMENT_ID | Enables the configured Google Analytics measurement stream. |
| Error monitoring | Optional | NEXT_PUBLIC_SENTRY_DSN, SENTRY_ORG, SENTRY_PROJECT, SENTRY_AUTH_TOKEN | Public DSN used by client, server, and edge Sentry SDKs, and release/source-map configuration. |
| Notification routing | Optional | LEAD_ALERT_EMAIL, SYSTEM_ALERT_EMAIL, BILLING_ALERT_EMAIL | Routes category alerts; each value falls back to the configured super-admin email. |
| Security baseline | Required or recommended for production | CRON_SECRET, RATE_LIMIT_FAIL_MODE, TRUST_PROXY_HEADERS | Protects scheduled routes, controls limiter failure behavior, and defines trusted proxy handling. |
| Billing runtime | Required when billing is enabled | BILLING_PROVIDER, BILLING_PROVIDER_LOCKED, BILLING_ENABLED_MODELS, BILLING_MODELS_LOCKED, BILLING_PRESET, BILLING_CATALOG_JSON, BILLING_PORTAL_CONFIGURATION_ID, BILLING_SUBSCRIPTION_EXPIRING_SOON_DAYS, BILLING_DEMO_ACTIONS_ENABLED | Selects the provider and models, defines the sellable catalog, and controls portal and expiry behavior. |
| Stripe | Required when Stripe is active | STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET | Authorizes Stripe API calls and verifies billing webhook signatures. |
| Lemon Squeezy | Required when Lemon Squeezy is active | LEMONSQUEEZY_API_KEY, LEMONSQUEEZY_STORE_ID, LEMONSQUEEZY_WEBHOOK_SECRET | Authorizes store operations and verifies Lemon Squeezy webhook signatures. |
| Email delivery | Required when email is enabled | RESEND_API_KEY, RESEND_SENDER_EMAIL, RESEND_REPLY_TO_EMAIL, RESEND_WEBHOOK_SECRET | Configures Resend delivery identity, reply handling, and delivery-status webhook verification. |
| CMS remote image import | Optional | CMS_REMOTE_IMAGE_IMPORT_ENABLED, CMS_REMOTE_IMAGE_ALLOWED_HOSTS | Enables server-side remote image imports and restricts hosts. |
| Bot protection and waitlist confirmation | Optional | NEXT_PUBLIC_TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY, WAITLIST_TURNSTILE_REQUIRED, WAITLIST_DOUBLE_OPT_IN_ENABLED, WAITLIST_DOUBLE_OPT_IN_TTL_MINUTES | Controls Turnstile enforcement and waitlist double-opt-in behavior. |
| Retention | Optional overrides | RETENTION_DAYS_WEBHOOK_EVENTS, RETENTION_DAYS_OUTBOX_SENT, RETENTION_DAYS_AUDIT_LOG, RETENTION_DAYS_RATE_LIMITS, RETENTION_BATCH_SIZE | Overrides cleanup windows for operational records handled by the retention job. |
| Rate-limit policies | Optional overrides | RATE_LIMIT_BILLING_CHECKOUT_LIMIT, RATE_LIMIT_BILLING_CHECKOUT_WINDOW_SECONDS, RATE_LIMIT_BILLING_PORTAL_LIMIT, RATE_LIMIT_BILLING_PORTAL_WINDOW_SECONDS, RATE_LIMIT_BILLING_EXPORT_LIMIT, RATE_LIMIT_BILLING_EXPORT_WINDOW_SECONDS, RATE_LIMIT_WAITLIST_SIGNUP_LIMIT, RATE_LIMIT_WAITLIST_SIGNUP_WINDOW_SECONDS, RATE_LIMIT_WAITLIST_CONFIRM_LIMIT, RATE_LIMIT_WAITLIST_CONFIRM_WINDOW_SECONDS, RATE_LIMIT_WAITLIST_EXPORT_LIMIT, RATE_LIMIT_WAITLIST_EXPORT_WINDOW_SECONDS, RATE_LIMIT_PUBLIC_CONTACT_LIMIT, RATE_LIMIT_PUBLIC_CONTACT_WINDOW_SECONDS, RATE_LIMIT_WEBHOOK_STRIPE_LIMIT, RATE_LIMIT_WEBHOOK_STRIPE_WINDOW_SECONDS, RATE_LIMIT_WEBHOOK_LEMONSQUEEZY_LIMIT, RATE_LIMIT_WEBHOOK_LEMONSQUEEZY_WINDOW_SECONDS, RATE_LIMIT_WEBHOOK_RESEND_LIMIT, RATE_LIMIT_WEBHOOK_RESEND_WINDOW_SECONDS, RATE_LIMIT_SCHEDULER_PUBLISH_LIMIT, RATE_LIMIT_SCHEDULER_PUBLISH_WINDOW_SECONDS, RATE_LIMIT_CRON_NOTIFICATION_OUTBOX_LIMIT, RATE_LIMIT_CRON_NOTIFICATION_OUTBOX_WINDOW_SECONDS, RATE_LIMIT_CRON_DATA_RETENTION_LIMIT, RATE_LIMIT_CRON_DATA_RETENTION_WINDOW_SECONDS | Overrides the default request count and time window for each protected route family. |
| Local E2E | Testing only | E2E_PORT, E2E_BASE_URL, E2E_WEB_SERVER_COMMAND, E2E_RECORD_VIDEO, E2E_RUN_ID, E2E_ENABLE_MUTATING_FLOWS, E2E_USER_EMAIL, E2E_USER_PASSWORD, E2E_SUPER_ADMIN_EMAIL, E2E_SUPER_ADMIN_PASSWORD, E2E_READ_ONLY_ADMIN_EMAIL, E2E_READ_ONLY_ADMIN_PASSWORD | Configures local Playwright targets, recording, run isolation, and optional test identities. |
Public URL validation
Source: src/lib/config.ts
Public values are normalized centrally, while provider secrets stay in server-owned modules.
ts
const publicEnvSchema = z.object({
NEXT_PUBLIC_SITE_URL: optionalPublicUrl("NEXT_PUBLIC_SITE_URL"),
NEXT_PUBLIC_SITE_NAME: z.string().default(appIdentity.defaultSiteName),
NEXT_PUBLIC_SUPPORT_EMAIL: z.string().email().optional(),
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
});Environment rules
- Copy the application env template and keep it as the canonical name inventory.
- Never expose Supabase secret, billing, email, Turnstile, or webhook keys through a NEXT_PUBLIC_ variable.
- Enable only the provider groups the deployment actually uses.
- Keep E2E identities and mutation toggles out of production.
- After changing env values, verify /api/health, auth, billing setup, email delivery, and protected cron routes.