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.

The easiest way to configure production environment variables is using the Dev Tools application:

  1. Run Dev Tools: pnpm --filter dev-tool dev
  2. Open http://localhost:3010/variables
  3. Select Production mode from the dropdown
  4. Fill in missing variables (highlighted in red)
  5. Click Copy to copy all variables
  6. 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/database

Your PostgreSQL connection string. Get this from your database provider (Neon, PlanetScale, Supabase, Railway, etc.).

Site URL

NEXT_PUBLIC_SITE_URL=https://your-domain.com

Your production domain. Must match exactly - used for authentication callbacks, emails, and absolute URLs.

Authentication Secret

BETTER_AUTH_SECRET=your-random-secret-string

A 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 32

Billing Provider

NEXT_PUBLIC_BILLING_PROVIDER=stripe

Set 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.com
STORAGE_S3_ACCESS_KEY_ID=...
STORAGE_S3_SECRET_ACCESS_KEY=...
STORAGE_S3_BUCKET=your-bucket-name
STORAGE_S3_REGION=us-east-1

Required for file uploads. Works with AWS S3, Cloudflare R2, Railway Storage, or any S3-compatible provider.

Email

EMAIL_SENDER=noreply@your-domain.com

Plus your email provider credentials. Here's an example for Resend (recommended):

EMAIL_SENDER=noreply@your-domain.com
RESEND_API_KEY=re_...

For other providers:

Postmark:

POSTMARK_API_KEY=...

SendGrid:

SENDGRID_API_KEY=...

SMTP (generic):

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_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=...

Feature Flags

NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true

Match these to your development configuration. For organization/team settings, use NEXT_PUBLIC_ACCOUNT_MODE (see Account Modes).

Environment Variables Reference

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string
NEXT_PUBLIC_SITE_URLYesProduction domain URL
BETTER_AUTH_SECRETYesAuthentication token signing secret
NEXT_PUBLIC_BILLING_PROVIDERYesstripe or polar
STRIPE_SECRET_KEYIf StripeStripe secret key
STRIPE_WEBHOOK_SECRETIf StripeStripe webhook signing secret
POLAR_ACCESS_TOKENIf PolarPolar API token
STORAGE_BASE_URLYesS3 endpoint URL
STORAGE_S3_ACCESS_KEY_IDYesS3 access key
STORAGE_S3_SECRET_ACCESS_KEYYesS3 secret key
STORAGE_S3_BUCKETYesS3 bucket name
STORAGE_S3_REGIONYesS3 region
EMAIL_SENDERYesFrom email address

For the complete list, see the Environment Variables Reference.

Best Practices

  1. Never commit secrets - Use .env.local for local development, never commit to git
  2. Use different values per environment - Don't reuse development keys in production
  3. Validate before deploying - Use Dev Tools to check all required variables are set
  4. Rotate secrets regularly - Especially after team member changes
  5. 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.