Environment Variables Reference
Complete reference guide for all environment variables used in the Next.js Prisma SaaS Kit.
Configure your MakerKit application using environment variables for database connections, authentication secrets, billing providers, email, and more. This reference covers every variable with defaults and usage examples.
Environment variables are key-value pairs that configure application behavior without hardcoding values. MakerKit uses .env files for development and platform-specific settings (Vercel, Docker) for production.
This page is part of the Configuration documentation.
Quick Start
The minimum required variables to run locally:
# apps/web/.env.localDATABASE_URL="postgresql://user:pass@localhost:5432/mydb"BETTER_AUTH_SECRET="generate-with-openssl-rand-base64-32"NEXT_PUBLIC_SITE_URL="http://localhost:3000"NEXT_PUBLIC_PRODUCT_NAME="My SaaS"EMAIL_SENDER="My SaaS <noreply@example.com>"Use environment variables when: the value changes per environment, contains secrets, or needs to be changed without redeploying.
Use config files when: you need TypeScript validation, complex objects, or the value is truly static.
If unsure: environment variables are the safe default for anything that might differ between dev and production.
Runtime Environment Variables
This kit supports runtime environment variables using next-runtime-env, enabling "build once, deploy many" workflows for Docker deployments. This differs from standard Next.js behavior where NEXT_PUBLIC_* variables are inlined at build time.
How It Works
- Server Components: Use
process.envdirectly (evaluated at runtime on server) - Client Components: Use
env()from@kit/shared/env(reads from injected script) - Config files: Use
env()with lazy evaluation via Proxy pattern
Using env() in Client Components
'use client';import { env } from '@kit/shared/env';export function MyComponent() { // Runtime value - changes based on deployment environment const siteUrl = env('NEXT_PUBLIC_SITE_URL'); const appHome = env('NEXT_PUBLIC_APP_HOME_PATH') || '/dashboard'; return <a href={siteUrl}>{appHome}</a>;}Docker "Build Once, Deploy Many"
With runtime env vars, you can build a single Docker image and deploy to different environments:
# Build oncedocker build -t myapp .# Deploy to stagingdocker run -e NEXT_PUBLIC_SITE_URL=https://staging.example.com myapp# Deploy to productiondocker run -e NEXT_PUBLIC_SITE_URL=https://example.com myappWhen to Use Each Approach
| Context | Method | When Evaluated |
|---|---|---|
| Server Components | process.env.NEXT_PUBLIC_* | Runtime (on server) |
| Client Components | env('NEXT_PUBLIC_*') | Runtime (in browser) |
Build-time config (next.config.ts) | process.env.* | Build time only |
Database
To connect to your database, set the DATABASE_URL environment variable. This is passed directly to Prisma ORM for connection pooling and query execution.
# PostgreSQL connection stringDATABASE_URL="postgresql://user:password@host:port/database"The connection string format depends on your database provider. Prisma supports PostgreSQL, MySQL, SQLite, SQL Server, MongoDB, and CockroachDB.
Authentication
The authentication secret is used by Better Auth to sign sessions. It must be a random string of at least 32 characters.
# Secret for signing sessions (min 32 characters)# Generate with: openssl rand -base64 32BETTER_AUTH_SECRET="your-random-secret-here"# Base URL of your applicationNEXT_PUBLIC_SITE_URL="http://localhost:3000" # Development# NEXT_PUBLIC_SITE_URL="https://yourdomain.com" # ProductionBETTER_AUTH_SECRET: The authentication secret used by Better Auth to sign sessions. Must be a random string of at least 32 characters.NEXT_PUBLIC_SITE_URL: The base URL of your application. When in production, it must use a valid HTTPS URL.
Application Settings
# Application name (displayed in UI)NEXT_PUBLIC_PRODUCT_NAME="Makerkit"# Site URL (for absolute links)NEXT_PUBLIC_SITE_URL="http://localhost:3000"# Default languageNEXT_PUBLIC_DEFAULT_LOCALE="en"# Theme settingsNEXT_PUBLIC_DEFAULT_THEME_MODE="light" # or "dark" or "system"NEXT_PUBLIC_PRODUCT_NAME: The name of your application, displayed in the UINEXT_PUBLIC_SITE_URL: The base URL of your applicationNEXT_PUBLIC_DEFAULT_LOCALE: The default language of your applicationNEXT_PUBLIC_DEFAULT_THEME_MODE: The default theme mode of your application
Account Mode
Account mode is used to determine the default context for the application.
# Account mode (see Account Modes documentation)NEXT_PUBLIC_ACCOUNT_MODE="hybrid" # personal-only | organizations-only | hybridNEXT_PUBLIC_ACCOUNT_MODE: The account mode of your application. See Account Modes for more information.
Authentication Features
The variables below are used to specify settings related to authentication:
# Enable email/password authenticationNEXT_PUBLIC_AUTH_PASSWORD=true# Enable magic link authenticationNEXT_PUBLIC_AUTH_MAGIC_LINK=false# OAuth providers (comma-separated)NEXT_PUBLIC_AUTH_OAUTH_PROVIDERS="google" # google,github,apple# Password requirementsNEXT_PUBLIC_PASSWORD_REQUIRE_SPECIAL_CHARS=falseNEXT_PUBLIC_PASSWORD_REQUIRE_NUMBERS=falseNEXT_PUBLIC_PASSWORD_REQUIRE_UPPERCASE=false# Display terms and conditions checkboxNEXT_PUBLIC_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX=falseNEXT_PUBLIC_AUTH_PASSWORD: Whether to enable email/password authentication. Default istrue.NEXT_PUBLIC_AUTH_MAGIC_LINK: Whether to enable magic link authentication. Default isfalse.NEXT_PUBLIC_AUTH_OAUTH_PROVIDERS: The OAuth providers to enable as a comma-separated list (ex.google,github,apple). Default isgoogle.NEXT_PUBLIC_PASSWORD_REQUIRE_SPECIAL_CHARS: Whether to require special characters in passwords. Default isfalse.NEXT_PUBLIC_PASSWORD_REQUIRE_NUMBERS: Whether to require numbers in passwords. Default isfalse.NEXT_PUBLIC_PASSWORD_REQUIRE_UPPERCASE: Whether to require uppercase letters in passwords. Default isfalse.NEXT_PUBLIC_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX: Whether to display the terms and conditions checkbox during sign-up. Default isfalse.
Feature Flags
The variables below are used to specify settings related to feature flags:
# OrganizationsNEXT_PUBLIC_ALLOW_USER_TO_CREATE_ORGANIZATION=true# Custom roles/permissionsNEXT_PUBLIC_ENABLE_CUSTOM_ROLES=falseNEXT_PUBLIC_ALLOW_USER_TO_CREATE_ORGANIZATION: Whether to allow users to create organizations. Default istrue.NEXT_PUBLIC_ENABLE_CUSTOM_ROLES: Whether to enable custom roles. Default isfalse. Please bear in mind this is currently an experimental feature and is not yet available for usage.
Note: Organization/team account settings are controlled by NEXT_PUBLIC_ACCOUNT_MODE. See Account Modes for details.
Captcha
The captcha plugin adds bot protection to authentication flows using Cloudflare Turnstile:
# Captcha (Cloudflare Turnstile)TURNSTILE_SECRET_KEY=""NEXT_PUBLIC_CAPTCHA_SITE_KEY=""TURNSTILE_SECRET_KEY: The secret key for Cloudflare Turnstile.NEXT_PUBLIC_CAPTCHA_SITE_KEY: The site key for Cloudflare Turnstile.
Both are not provided/enabled by default.
Invitation Settings
The variables below are used to specify settings related to invitations:
NEXT_PUBLIC_INVITATION_EXPIRES_IN=604800NEXT_PUBLIC_INVITATION_EXPIRES_IN: The expiration time for invitations in seconds. Default is604800(7 days).
Email Configuration
The variables below are used to specify settings related to email configuration. If you use nodemailer (which is used by default), refer to the SMTP settings. If you use resend, refer to the Resend settings.
# Email provider (nodemailer or resend)MAILER_PROVIDER="nodemailer"# Sender addressEMAIL_SENDER="Your App <noreply@yourdomain.com>"MAILER_PROVIDER: The email provider to use. Default isnodemailer.EMAIL_SENDER: The sender address for emails. Default isYour App <noreply@yourdomain.com>.
For Nodemailer (SMTP)
If you use nodemailer (which is used by default), you need to set the SMTP configuration:
EMAIL_HOST="smtp.example.com"EMAIL_PORT=587EMAIL_TLS=trueEMAIL_USER="your_username"EMAIL_PASSWORD="your_password"EMAIL_HOST: The SMTP host for Nodemailer.EMAIL_PORT: The SMTP port for Nodemailer.EMAIL_TLS: Whether to use TLS for Nodemailer.EMAIL_USER: The username for Nodemailer.EMAIL_PASSWORD: The password for Nodemailer.
For Resend
If you use resend, you need to set the Resend API key:
MAILER_PROVIDER="resend"RESEND_API_KEY="re_your_api_key"MAILER_PROVIDER: Useresendto use Resend as the email provider.RESEND_API_KEY: The API key for Resend whenMAILER_PROVIDERis set toresend.
Storage Configuration
The Storage configuration uses unstorage as a unified interface for storage providers. This means that you can use the same API to interact with different storage providers.
During local development, we store files in the ./public/storage.dev folder:
Local Storage (Development):
STORAGE_PROVIDER="fs"STORAGE_BASE_URL="/storage.dev"If you use AWS S3 or any S3-compatible provider (such as Cloudflare R2) you can use the following configuration:
STORAGE_S3_ACCESS_KEY_ID="your-access-key"STORAGE_S3_SECRET_ACCESS_KEY="your-secret-key"STORAGE_S3_ENDPOINT="your-endpoint"STORAGE_S3_BUCKET="your-bucket"STORAGE_S3_REGION="your-region"STORAGE_S3_ACCESS_KEY_ID: The access key ID for the S3 bucket.STORAGE_S3_SECRET_ACCESS_KEY: The secret access key for the S3 bucket.STORAGE_S3_ENDPOINT: The endpoint for the S3 bucket.STORAGE_S3_BUCKET: The name of the S3 bucket.STORAGE_S3_REGION: The region of the S3 bucket.
Billing
The variables below are used to specify settings related to billing:
# Billing providerNEXT_PUBLIC_BILLING_PROVIDER="stripe" # or polar# StripeSTRIPE_SECRET_KEY="sk_test_..."STRIPE_WEBHOOK_SECRET="whsec_..."NEXT_PUBLIC_BILLING_PROVIDER: The billing provider to use. Default isstripe. Supported values arestripeandpolar.STRIPE_SECRET_KEY: The secret key for Stripe.STRIPE_WEBHOOK_SECRET: The webhook secret for Stripe.
If using Polar, please provide the following environment variables:
NEXT_PUBLIC_BILLING_PROVIDER="polar"POLAR_ACCESS_TOKEN=********Monitoring & Analytics
The variables below are used to specify settings related to monitoring and analytics:
# Sentry (error tracking)NEXT_PUBLIC_SENTRY_DSN="https://...@sentry.io/..."# Sentry environmentNEXT_PUBLIC_SENTRY_ENVIRONMENT=development# Analytics providerNEXT_PUBLIC_MONITORING_PROVIDER="sentry"NEXT_PUBLIC_SENTRY_DSN: The Sentry DSN for error tracking.NEXT_PUBLIC_SENTRY_ENVIRONMENT: The environment for Sentry. Default isdevelopment.NEXT_PUBLIC_MONITORING_PROVIDER: The monitoring provider to use. Default issentry. At this time,sentryis the only supported value.
CMS
The variables below are used to specify settings related to the CMS:
CMS_CLIENT=keystatic# Keystatic configurationNEXT_PUBLIC_KEYSTATIC_CONTENT_PATH=./contentNEXT_PUBLIC_KEYSTATIC_STORAGE_KIND=local# Keystatic storage options (for GitHub/Cloud storage)# NEXT_PUBLIC_KEYSTATIC_STORAGE_REPO=# KEYSTATIC_STORAGE_PROJECT=# KEYSTATIC_STORAGE_BRANCH_PREFIX=# KEYSTATIC_PATH_PREFIX=# Keystatic GitHub token (SENSITIVE: Set in .env.local or deployment environment)# KEYSTATIC_GITHUB_TOKEN=CMS_CLIENT: The CMS client to use. Default iskeystatic. At this time,keystaticis the only supported value.NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH: The path to the content for the CMS. Default is./content.NEXT_PUBLIC_KEYSTATIC_STORAGE_KIND: The storage kind for the CMS. Default islocal. At this time,localis the only supported value.NEXT_PUBLIC_KEYSTATIC_STORAGE_REPO: The repository for the CMS. Default isundefined.NEXT_PUBLIC_KEYSTATIC_STORAGE_BRANCH_PREFIX: The branch prefix for the CMS. Default isundefined.NEXT_PUBLIC_KEYSTATIC_PATH_PREFIX: The path prefix for the CMS. Default isundefined.KEYSTATIC_GITHUB_TOKEN: The GitHub token for the CMS when using GitHub as the storage provider. This is a sensitive value and should not use theNEXT_PUBLIC_prefix. Default isundefined.
Logger
The variables below are used to specify settings related to the logger:
LOGGER=pinoLOGGER: The logger to use. Possible values arepinoorconsole. Default ispino. Theconsolevalue falls back to the built-inconsolemodule in Node.js.
Environment Files
.env
Purpose: Public, non-sensitive configuration shared across all environments
Committed to git: ✅ Yes
Contains:
- Public configuration
- Feature flags
- Default settings
- Paths and URLs (without secrets)
.env.development
Purpose: Development-specific configuration
Committed to git: ✅ Yes
Contains:
- Development database URLs
- Local email settings
- Development API keys (test mode)
.env.local
Purpose: Local secrets and overrides
Committed to git: ⛔ NO (git-ignored)
Contains:
- Database credentials
- API keys and secrets
- Authentication secrets
- Personal configuration overrides
Security: Never commit this file!
Production Environment Variables
For production deployments, you should set environment variables directly in your hosting platform (Vercel, Railway, Docker, etc.) rather than using a .env.production file. This is the recommended approach for:
- Database credentials
- API keys and secrets
- Authentication secrets
- Production URLs
Public vs Private Variables
Public Variables (NEXT_PUBLIC_*)
Accessible: Client and server
Security: ⚠️ Exposed in browser: please be careful not to expose sensitive information to the client.
Use for:
- Site URLs
- Application names
- Public API keys (ex. Stripe publishable key)
- Feature flags (non-sensitive)
Example:
NEXT_PUBLIC_SITE_URL="https://example.com"Usage:
// Works in both client and server componentsconst siteUrl = process.env.NEXT_PUBLIC_SITE_URL;Private Variables
Accessible: Server only
Security: ✅ Never exposed to browser
Use for:
- Database credentials
- API secrets
- Authentication secrets
- Private API keys
Example:
DATABASE_URL="postgresql://..."BETTER_AUTH_SECRET="secret"STRIPE_SECRET_KEY="sk_test_..."Usage:
// Only works in server components, API routes, and server actionsconst dbUrl = process.env.DATABASE_URL;Build & Performance Settings
The variables below control build-time and runtime performance features:
# Enable React Compiler (experimental)ENABLE_REACT_COMPILER=false# Enable strict Content Security PolicyENABLE_STRICT_CSP=false# Disable Next.js telemetryNEXT_TELEMETRY_DISABLED=1ENABLE_REACT_COMPILER: Enables the experimental React Compiler for automatic component memoization. Default isfalse. Enable with caution and test thoroughly.ENABLE_STRICT_CSP: Enables strict Content Security Policy headers via@nosecone/nextfor enhanced security against XSS and clickjacking. Default isfalse.NEXT_TELEMETRY_DISABLED: Disables Next.js anonymous telemetry data collection. Set to1to opt out. Default is1(disabled).
Version Updater
The version updater checks for new deployments and prompts users to reload:
# Enable version update notificationsNEXT_PUBLIC_ENABLE_VERSION_UPDATER=false# How often to check for updates (in seconds)NEXT_PUBLIC_VERSION_UPDATER_REFETCH_INTERVAL_SECONDS=3600NEXT_PUBLIC_ENABLE_VERSION_UPDATER: Whether to show a dialog when a new version is deployed. Default isfalse.NEXT_PUBLIC_VERSION_UPDATER_REFETCH_INTERVAL_SECONDS: How frequently to check for new versions, in seconds. Must be between 1 and 86400 (1 second to 24 hours). Default is3600(1 hour).
Keystatic Path Prefix
When using Keystatic with GitHub or Cloud storage, you may need to specify a path prefix:
# Path prefix for Keystatic content in your repositoryKEYSTATIC_PATH_PREFIX=apps/webKEYSTATIC_PATH_PREFIX: The directory path within your repository where Keystatic content is stored. Required when using GitHub storage kind. Default isapps/web.
Security Best Practices
1. Never Commit Secrets
# ✅ In .gitignore (already configured).env.local.env.*.local2. Use Different Secrets Per Environment
# DevelopmentBETTER_AUTH_SECRET="dev_secret_123abc..."# Production (different secret!)BETTER_AUTH_SECRET="prod_secret_xyz789..."Minimum Environment Variables
The minimum required environment variables to run the application in a local environment are:
# Site ConfigurationNEXT_PUBLIC_SITE_URL=NEXT_PUBLIC_PRODUCT_NAME=# EmailMAILER_PROVIDER=nodemailerEMAIL_SENDER=EMAIL_HOST=EMAIL_PORT=EMAIL_USER=EMAIL_PASSWORD=EMAIL_TLS=# BillingNEXT_PUBLIC_BILLING_PROVIDER=stripeSTRIPE_WEBHOOK_SECRET=STRIPE_SECRET_KEY=# DatabaseBETTER_AUTH_SECRET=DATABASE_URL=This is the set of variables that you must have to run the application - and excludes all the default values for the variables which the kit provides by default.
If you add certain values, such as google to NEXT_PUBLIC_AUTH_OAUTH_PROVIDERS, you must also set the GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables - and so on.
The best way to set these variables is to use the Dev Tools at port 3010 - Read the documentation.
Common Pitfalls
- Forgetting to restart the dev server: Next.js reads environment variables at startup. After changing
.envfiles, restart withpnpm dev. - Using
NEXT_PUBLIC_for secrets: Variables with this prefix are bundled into client JavaScript and visible in the browser. Never prefix API keys, database URLs, or auth secrets. - Trailing slash in
NEXT_PUBLIC_SITE_URL: Causes broken OAuth redirects and double-slash URLs. Usehttps://example.comnothttps://example.com/. - Same secrets across environments: Using identical
BETTER_AUTH_SECRETin dev and production is a security risk. Generate unique secrets per environment. - Missing OAuth provider credentials: If you add
googletoNEXT_PUBLIC_AUTH_OAUTH_PROVIDERS, you must also setGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET. - Unquoted values with special characters: Wrap values containing
#,$, or spaces in quotes:EMAIL_PASSWORD="my#complex$pass". - Committing
.env.local: This file should be git-ignored. If you accidentally commit secrets, rotate them immediately.
Frequently Asked Questions
Where should I put production environment variables?
Can I use different .env files for staging vs production?
Why is my environment variable not updating?
How do I debug which variables are loaded?
What is the difference between .env and .env.local?
Next: Feature Flags →