Environment Setup
Configure production environment variables and secrets.
Production environment setup involves configuring database connections, authentication secrets, billing provider credentials, S3-compatible storage, and email services. Use the Dev Tools application to generate a complete .env.production.local file, or manually set variables in your hosting platform's dashboard. All NEXT_PUBLIC_* variables must be set before building—they're embedded at build time, not runtime.
This guide covers the essential variables and how to set them up.
Using Dev Tools (Recommended)
The easiest way to configure production environment variables is using the Dev Tools application:
- Run Dev Tools:
pnpm --filter dev-tool dev - Open
http://localhost:3010/variables - Select Production mode from the dropdown
- Fill in missing variables (highlighted in red)
- Click Copy to copy all variables
- Paste into your hosting provider's environment settings
For more details, see the Dev Tools documentation.
Required Environment Variables
Database
DATABASE_URL=postgresql://user:password@host:5432/databaseYour PostgreSQL connection string. Get this from your database provider (Neon, PlanetScale, Supabase, Railway, etc.).
Site URL
NEXT_PUBLIC_SITE_URL=https://your-domain.comYour production domain. Must match exactly - used for authentication callbacks, emails, and absolute URLs.
Authentication Secret
BETTER_AUTH_SECRET=your-random-secret-stringA random secret string used to sign authentication tokens and cookies. Generate a secure random string (at least 32 characters). You can generate one using:
openssl rand -base64 32Security Critical
Use a unique, randomly generated secret for production. Never reuse your development secret or share it publicly.
Billing Provider
NEXT_PUBLIC_BILLING_PROVIDER=stripeSet to stripe or polar depending on your billing provider.
For Stripe:
STRIPE_SECRET_KEY=sk_live_...STRIPE_WEBHOOK_SECRET=whsec_...For Polar:
POLAR_ACCESS_TOKEN=...Storage (S3-Compatible)
STORAGE_BASE_URL=https://your-bucket-endpoint.comSTORAGE_S3_ACCESS_KEY_ID=...STORAGE_S3_SECRET_ACCESS_KEY=...STORAGE_S3_BUCKET=your-bucket-nameSTORAGE_S3_REGION=us-east-1Required for file uploads. Works with AWS S3, Cloudflare R2, Railway Storage, or any S3-compatible provider.
EMAIL_SENDER=noreply@your-domain.comPlus your email provider credentials. Here's an example for Resend (recommended):
EMAIL_SENDER=noreply@your-domain.comRESEND_API_KEY=re_...For other providers:
Postmark:
POSTMARK_API_KEY=...SendGrid:
SENDGRID_API_KEY=...SMTP (generic):
SMTP_HOST=smtp.example.comSMTP_PORT=587SMTP_USER=...SMTP_PASSWORD=...See the Email Configuration guide for detailed setup instructions.
Optional Environment Variables
OAuth Providers
If you enabled social login during development:
Google:
GOOGLE_CLIENT_ID=...GOOGLE_CLIENT_SECRET=...GitHub:
GITHUB_CLIENT_ID=...GITHUB_CLIENT_SECRET=...OAuth Redirect URLs
Remember to add your production domain to the OAuth provider's allowed redirect URLs.
Feature Flags
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=trueMatch these to your development configuration. For organization/team settings, use NEXT_PUBLIC_ACCOUNT_MODE (see Account Modes).
Environment Variables Reference
| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Yes | PostgreSQL connection string |
NEXT_PUBLIC_SITE_URL | Yes | Production domain URL |
BETTER_AUTH_SECRET | Yes | Authentication token signing secret |
NEXT_PUBLIC_BILLING_PROVIDER | Yes | stripe or polar |
STRIPE_SECRET_KEY | If Stripe | Stripe secret key |
STRIPE_WEBHOOK_SECRET | If Stripe | Stripe webhook signing secret |
POLAR_ACCESS_TOKEN | If Polar | Polar API token |
STORAGE_BASE_URL | Yes | S3 endpoint URL |
STORAGE_S3_ACCESS_KEY_ID | Yes | S3 access key |
STORAGE_S3_SECRET_ACCESS_KEY | Yes | S3 secret key |
STORAGE_S3_BUCKET | Yes | S3 bucket name |
STORAGE_S3_REGION | Yes | S3 region |
EMAIL_SENDER | Yes | From email address |
For the complete list, see the Environment Variables Reference.
Best Practices
- Never commit secrets - Use
.env.localfor local development, never commit to git - Use different values per environment - Don't reuse development keys in production
- Validate before deploying - Use Dev Tools to check all required variables are set
- Rotate secrets regularly - Especially after team member changes
- Use your provider's secret management - Most hosting platforms encrypt environment variables
Common Mistakes
Wrong site URL
NEXT_PUBLIC_SITE_URL must match your actual domain exactly, including https://.
Symptoms: Authentication callbacks fail, email links point to wrong domain, OAuth redirects break.
Fix: Set NEXT_PUBLIC_SITE_URL=https://your-actual-domain.com (no trailing slash). Redeploy after changing since it's a NEXT_PUBLIC_ variable.
Missing webhook secrets
Billing won't work without webhook configuration.
Symptoms: Subscriptions don't activate after payment, webhook endpoint returns 401/403 errors.
Fix: Copy the webhook signing secret from your Stripe Dashboard → Developers → Webhooks → Your endpoint → Signing secret. Set as STRIPE_WEBHOOK_SECRET.
Development keys in production
Stripe test keys (sk_test_*) won't process real payments.
Symptoms: Payments work in test mode but fail with real cards, or test data appears in production.
Fix: In Stripe Dashboard, toggle to "Live mode" and copy the live secret key (sk_live_*). Update STRIPE_SECRET_KEY and create a new webhook endpoint for production.
Typos in variable names
Environment variables are case-sensitive and must match exactly.
Symptoms: Application crashes on startup with "missing required environment variable" errors.
Fix: Double-check spelling, especially for NEXT_PUBLIC_ prefix. Use the Dev Tools validator to catch missing or misnamed variables before deploying.
NEXT_PUBLIC_* variables added after build
Variables prefixed with NEXT_PUBLIC_ are embedded at build time, not read at runtime.
Symptoms: Client-side code shows undefined for environment variables that are definitely set.
Fix: Set all NEXT_PUBLIC_* variables in your hosting platform's settings, then trigger a new build and deployment.