Production Environment Variables for Next.js Supabase SaaS

Complete reference for generating and configuring production environment variables in your MakerKit Next.js Supabase application.

Generate and configure environment variables for your MakerKit Next.js Supabase Turbo production deployment. MakerKit uses Zod schemas to validate all variables at build time, catching configuration errors before deployment.

Generate Environment Variables

MakerKit provides an interactive generator that walks you through each required variable:

pnpm turbo gen env

This command:

  1. Prompts you for each variable value
  2. Uses defaults from your existing .env files when available
  3. Creates a file at turbo/generators/templates/env/.env.local

Copy the contents of this file to your hosting provider's environment variable settings.


Validate Environment Variables

After generating or manually setting variables, validate them:

turbo gen validate-env

This checks that all required variables are present and correctly formatted.


Required Variables Reference

Application Settings

VariableDescriptionExample
NEXT_PUBLIC_SITE_URLYour production URL (no trailing slash)https://yourdomain.com
NEXT_PUBLIC_PRODUCT_NAMEProduct name shown in UIMyApp
NEXT_PUBLIC_SITE_TITLEBrowser tab titleMyApp - Build faster
NEXT_PUBLIC_SITE_DESCRIPTIONMeta description for SEOThe fastest way to build SaaS
NEXT_PUBLIC_DEFAULT_THEME_MODEDefault themelight, dark, or system
NEXT_PUBLIC_DEFAULT_LOCALEDefault languageen

Supabase Configuration

VariableDescriptionWhere to Find
NEXT_PUBLIC_SUPABASE_URLSupabase project URLDashboard > Settings > API
NEXT_PUBLIC_SUPABASE_PUBLIC_KEYSupabase anon keyDashboard > Settings > API
SUPABASE_SECRET_KEYSupabase service role keyDashboard > Settings > API
SUPABASE_DB_WEBHOOK_SECRETSecret for webhook authenticationGenerate with openssl rand -base64 32

Authentication Settings

VariableDescriptionDefault
NEXT_PUBLIC_AUTH_PASSWORDEnable email/password logintrue
NEXT_PUBLIC_AUTH_MAGIC_LINKEnable magic link loginfalse

Feature Flags

VariableDescriptionDefault
NEXT_PUBLIC_ENABLE_THEME_TOGGLEShow theme switcher in UItrue
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETIONAllow users to delete their accountfalse
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLINGEnable billing for personal accountsfalse
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTSEnable team/organization accountstrue
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETIONAllow team deletionfalse
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLINGEnable billing for teamsfalse
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATIONAllow creating new teamstrue
NEXT_PUBLIC_ENABLE_NOTIFICATIONSShow notification bell in UItrue
NEXT_PUBLIC_REALTIME_NOTIFICATIONSUse Supabase realtime for notificationsfalse
NEXT_PUBLIC_ENABLE_VERSION_UPDATERShow version update popupfalse

Billing Configuration

Stripe

VariableDescriptionWhere to Find
NEXT_PUBLIC_BILLING_PROVIDERSet to stripe-
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYStripe publishable keyStripe Dashboard > API Keys
STRIPE_SECRET_KEYStripe secret keyStripe Dashboard > API Keys
STRIPE_WEBHOOK_SECRETWebhook signing secretStripe Dashboard > Webhooks

Lemon Squeezy

VariableDescriptionWhere to Find
NEXT_PUBLIC_BILLING_PROVIDERSet to lemon-squeezy-
LEMON_SQUEEZY_SECRET_KEYAPI keyLemon Squeezy > Settings > API
LEMON_SQUEEZY_STORE_IDYour store IDLemon Squeezy > Settings > Store
LEMON_SQUEEZY_SIGNING_SECRETWebhook signing secretLemon Squeezy > Settings > Webhooks

Email Configuration

Using Resend

VariableValue
MAILER_PROVIDERresend
EMAIL_SENDERnoreply@yourdomain.com
RESEND_API_KEYYour Resend API key

Using Nodemailer (SMTP)

VariableDescription
MAILER_PROVIDERnodemailer
EMAIL_SENDERnoreply@yourdomain.com
EMAIL_HOSTSMTP host (e.g., smtp.sendgrid.net)
EMAIL_PORTSMTP port (usually 587 or 465)
EMAIL_USERSMTP username
EMAIL_PASSWORDSMTP password or API key
EMAIL_TLSEnable TLS (true or false)

CMS Configuration

VariableDescription
CMS_CLIENTCMS provider: keystatic or wordpress

Captcha Protection (Optional)

VariableDescription
NEXT_PUBLIC_CAPTCHA_SITE_KEYCloudflare Turnstile site key
CAPTCHA_SECRET_TOKENCloudflare Turnstile secret key

Monitoring (Optional)

VariableDescription
CONTACT_EMAILEmail for receiving contact form submissions
LOGGERLogger type: pino (default) or console

Environment Variable Groups

Minimum Required for Deployment

These are the absolute minimum variables needed for a working deployment:

# Application
NEXT_PUBLIC_SITE_URL=https://yourdomain.com
NEXT_PUBLIC_PRODUCT_NAME=MyApp
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLIC_KEY=eyJ...
SUPABASE_SECRET_KEY=eyJ...
# Billing (Stripe example)
NEXT_PUBLIC_BILLING_PROVIDER=stripe
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Email
MAILER_PROVIDER=resend
EMAIL_SENDER=noreply@yourdomain.com
RESEND_API_KEY=re_...
# Webhooks
SUPABASE_DB_WEBHOOK_SECRET=your-secret

Full Production Configuration

Here's a complete example with all common variables:

# ============================================
# APPLICATION
# ============================================
NEXT_PUBLIC_SITE_URL=https://yourdomain.com
NEXT_PUBLIC_PRODUCT_NAME=MyApp
NEXT_PUBLIC_SITE_TITLE=MyApp - Build SaaS Faster
NEXT_PUBLIC_SITE_DESCRIPTION=The complete SaaS starter kit
NEXT_PUBLIC_DEFAULT_THEME_MODE=light
NEXT_PUBLIC_DEFAULT_LOCALE=en
# ============================================
# AUTHENTICATION
# ============================================
NEXT_PUBLIC_AUTH_PASSWORD=true
NEXT_PUBLIC_AUTH_MAGIC_LINK=false
# ============================================
# FEATURES
# ============================================
NEXT_PUBLIC_ENABLE_THEME_TOGGLE=true
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION=true
NEXT_PUBLIC_ENABLE_PERSONAL_ACCOUNT_BILLING=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_BILLING=true
NEXT_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION=true
NEXT_PUBLIC_ENABLE_NOTIFICATIONS=true
NEXT_PUBLIC_REALTIME_NOTIFICATIONS=false
# ============================================
# SUPABASE
# ============================================
NEXT_PUBLIC_SUPABASE_URL=https://yourproject.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLIC_KEY=eyJhbGciOiJI...
SUPABASE_SECRET_KEY=eyJhbGciOiJI...
SUPABASE_DB_WEBHOOK_SECRET=your-webhook-secret
# ============================================
# BILLING (Stripe)
# ============================================
NEXT_PUBLIC_BILLING_PROVIDER=stripe
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# ============================================
# EMAIL
# ============================================
MAILER_PROVIDER=resend
EMAIL_SENDER=noreply@yourdomain.com
RESEND_API_KEY=re_...
# ============================================
# CMS
# ============================================
CMS_CLIENT=keystatic
# ============================================
# OPTIONAL
# ============================================
CONTACT_EMAIL=support@yourdomain.com
LOGGER=pino

Build-Time vs Runtime Variables

MakerKit uses Zod schemas to validate environment variables. Understanding when validation occurs helps debug issues:

Build-Time Validation

Variables prefixed with NEXT_PUBLIC_ are embedded at build time. If missing:

  • Build fails with a clear error message
  • You must add the variable and rebuild

Runtime Validation

Server-only variables (without NEXT_PUBLIC_ prefix) are validated when the server starts. If missing:

  • The application may start but fail when accessing certain features
  • Check server logs for validation errors

Secrets Management

What Counts as a Secret

These variables contain sensitive data and must be protected:

  • SUPABASE_SECRET_KEY
  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • LEMON_SQUEEZY_SECRET_KEY
  • LEMON_SQUEEZY_SIGNING_SECRET
  • SUPABASE_DB_WEBHOOK_SECRET
  • RESEND_API_KEY
  • EMAIL_PASSWORD
  • CAPTCHA_SECRET_TOKEN

Best Practices

  1. Never commit secrets: Use .gitignore to exclude .env*.local files
  2. Use hosting provider secrets: Vercel, Cloudflare, etc. have secure environment variable storage
  3. Rotate compromised secrets: If a secret is exposed, regenerate it immediately
  4. Limit access: Only give team members access to secrets they need

Platform-Specific Notes

Vercel

  • Add variables in Project Settings > Environment Variables
  • Separate variables by environment (Production, Preview, Development)
  • Use Vercel's sensitive variable feature for secrets

Cloudflare

  • Add variables to .dev.vars for local development
  • Use Wrangler secrets for production: wrangler secret put VARIABLE_NAME
  • Some variables may need to be in wrangler.toml for build-time access

Docker

  • Pass variables via --env-file flag
  • Never bake secrets into Docker images
  • Use Docker secrets or external secret managers for production

Troubleshooting

"Required environment variable X is missing"

The variable isn't set in your hosting provider. Add it and redeploy.

"Invalid value for environment variable X"

The variable value doesn't match the expected format. Check:

  • URLs should start with https:// and have no trailing slash
  • Boolean values should be true or false (not "true")
  • Provider names must match exactly (stripe, not Stripe)

Variables work locally but not in production

  1. Verify variables are set in your hosting provider (not just .env.local)
  2. Check for typos in variable names
  3. Ensure NEXT_PUBLIC_ prefix is correct for client-side variables
  4. Redeploy after adding variables (Vercel caches builds)

Secrets appearing in client-side code

Only variables with NEXT_PUBLIC_ prefix should be in client code. If server-only secrets appear:

  1. Check you're not importing server modules in client components
  2. Verify the variable name doesn't have NEXT_PUBLIC_ prefix
  3. Review your bundle with next build --analyze

Frequently Asked Questions

Why does MakerKit validate environment variables at build time?
Build-time validation catches configuration errors before deployment. Missing a critical variable like STRIPE_SECRET_KEY would otherwise cause runtime errors that are harder to debug. Zod schemas ensure all required variables are present and correctly formatted.
What's the difference between NEXT_PUBLIC_ and regular variables?
Variables prefixed with NEXT_PUBLIC_ are embedded in the client-side JavaScript bundle and visible to users. Never use this prefix for secrets. Regular variables are only available server-side and stay secure. This is a Next.js convention.
How do I add a new environment variable?
Add the variable to your hosting provider's settings, then redeploy. For client-side variables (NEXT_PUBLIC_), you must rebuild since they're embedded at build time. For server-only variables, a restart is usually sufficient.
Can I use different variables for staging and production?
Yes. Most hosting providers support environment-specific variables. Create separate Supabase projects for each environment, generate variables for each, and configure your hosting provider to use the right set based on the deployment environment.
What if I accidentally commit secrets to Git?
Immediately rotate all exposed credentials. Generate new API keys for Supabase, Stripe, and any other affected services. Consider using git-secrets or similar tools to prevent future accidental commits. Review Git history and consider rewriting it if the repo is private.

Next Steps