Multiple environments
Set up development, staging, and production environment variables for the web app.
For the complete documentation index, see llms.txt. Prefer markdown by appending.mdto documentation URLs or sendingAccept: text/markdown.
Use separate environments when you want local development, staging, and production to talk to different databases, auth callbacks, payment accounts, analytics projects, or feature flags.
The safe pattern is:
- keep variable names consistent across environments
- keep secrets out of Git
- expose only browser-safe values with
NEXT_PUBLIC_ - use
APP_ENVfor your own environment name instead of changingNODE_ENV
Good to know
Next.js treats NEXT_PUBLIC_ variables as client-side values. Anything with that prefix is bundled into the browser build, so never use it for database URLs, API secrets, webhook secrets, or private keys.
Choose your environments
Most apps only need three:
development- local work with local or sandbox servicesstaging- production-like testing before releaseproduction- the live customer environment
Use the same variable names in every environment. Only the values should change.
APP_ENV="development"
URL="http://localhost:3000"
DATABASE_URL=""
BETTER_AUTH_SECRET=""
BETTER_AUTH_URL="${URL}"
NEXT_PUBLIC_URL="${URL}"
NEXT_PUBLIC_APP_ENV="${APP_ENV}"Create local env files
For day-to-day development, keep local values in ignored .env.local files:
APP_ENV="development"
URL="http://localhost:3000"
DATABASE_URL="postgresql://user:password@localhost:5432/app"
BETTER_AUTH_SECRET="local-secret"
BETTER_AUTH_URL="${URL}"NEXT_PUBLIC_URL="${URL}"
NEXT_PUBLIC_APP_ENV="${APP_ENV}"
NEXT_PUBLIC_THEME_MODE="system"
NEXT_PUBLIC_THEME_COLOR="orange"The root file is a good place for shared server-side values. The app file is a good place for web-only values.
Add staging and production values
For local staging checks, create environment-specific local files:
APP_ENV="staging"
URL="https://staging.example.com"
DATABASE_URL="postgresql://..."
BETTER_AUTH_SECRET="..."
BETTER_AUTH_URL="${URL}"NEXT_PUBLIC_URL="${URL}"
NEXT_PUBLIC_APP_ENV="${APP_ENV}"
NEXT_PUBLIC_THEME_MODE="system"
NEXT_PUBLIC_THEME_COLOR="orange"Repeat the same shape for production:
APP_ENV="production"
URL="https://example.com"
DATABASE_URL="postgresql://..."
BETTER_AUTH_SECRET="..."
BETTER_AUTH_URL="${URL}"Do not commit secrets
Commit .env.example with empty or safe placeholder values. Keep .env.local, .env.staging.local, and .env.production.local ignored.
Add environment-aware scripts
The project already uses dotenv-cli, so you can load an environment by name with dotenv -c <environment>.
{
"scripts": {
"dev:web": "dotenv -c development -- turbo dev --filter=web",
"dev:web:staging": "dotenv -c staging -- turbo dev --filter=web",
"build:web:staging": "dotenv -c staging -- turbo build --filter=web",
"build:web:production": "dotenv -c production -- turbo build --filter=web"
}
}Then run:
pnpm dev:web:staging
pnpm build:web:productionThis loads .env, .env.<environment>, .env.local, and .env.<environment>.local in cascade order.
Configure your hosting provider
In your hosting provider, create separate environment groups or projects for staging and production.
Set the same variables there:
APP_ENV="production"
URL="https://example.com"
DATABASE_URL="postgresql://..."
BETTER_AUTH_SECRET="..."
BETTER_AUTH_URL="https://example.com"
NEXT_PUBLIC_URL="https://example.com"
NEXT_PUBLIC_APP_ENV="production"Before going live, verify:
- auth callback URLs point to the same environment
- webhooks point to the same environment
- payment providers use test keys in staging and live keys in production
- analytics and monitoring projects are separated or tagged by
APP_ENV NEXT_PUBLIC_values contain no secrets
Useful references
How is this guide?
Last updated on