Skip to content

Environment ​

Every project gets packages/env and a root .env.example. Copy that file to .env at the repo root and fill in values. .env is gitignored.

bash
cp .env.example .env

The Zod schema is generated from the apps, auth provider, payment provider, email provider, and ORM you selected. Empty required strings fail validation.

Loading the root .env ​

Generated app scripts, database commands, and the email preview use dotenv-cli to load ../../.env before starting. This works with pnpm dev, pnpm --filter @apps/next dev, or scripts run from inside an app directory. Variables already set in your shell or deployment environment take precedence over the root .env. A missing .env is allowed when the required variables are supplied externally.

Leave NODE_ENV unset in .env so frameworks can choose the correct mode for dev and production commands.

This applies to Next.js, Astro, Expo, Electron, Express, Fastify, TanStack Start, React Router, and every Vite framework and React variant, including apps created with --add. All generated app scripts except lint and format load the root file. Each stage of a chained command loads it separately.

Vite config files validate process.env, which is populated before Vite starts. In application code, pass import.meta.env to createViteEnv.

Turbo does not load .env itself. The generated globalDependencies: [".env"] makes changes to the root file invalidate cached tasks; globalEnv forwards the listed variables that are already in the process environment. Restart running dev commands after editing .env.

Server vs client ​

  • Server vars live on serverEnv (@packages/env/server) and are read from process.env.
  • Client vars use the prefix of each selected app family and are validated separately.
App typeClient prefixClient export
Next.jsNEXT_PUBLIC_nextEnv
AstroPUBLIC_astroEnv
ExpoEXPO_PUBLIC_expoEnv
Vite, Electron, TanStack Start, or React RouterVITE_createViteEnv(runtimeEnv) — pass import.meta.env
Express or Fastify—no client export; they import @packages/env/server on boot

Clerk and WorkOS also generate getPublicAuthConfig(), which reads the publishable key / client id from whichever of those prefixed names is set.

Variable matrix ​

WhenNameKindRequired
AlwaysNODE_ENVserverno (development | test | production)
Any database ORM (PostgreSQL or MySQL)DATABASE_URLserveryes (URL)
Any database ORM + SQLiteDATABASE_URLserveryes (string, e.g. file:./packages/db/local.db)
Better AuthBETTER_AUTH_SECRETserveryes
Better AuthBETTER_AUTH_URLserveryes (URL)
ClerkCLERK_SECRET_KEYserveryes
Clerk + NextNEXT_PUBLIC_CLERK_PUBLISHABLE_KEYclientyes
Clerk + AstroPUBLIC_CLERK_PUBLISHABLE_KEYclientyes
Clerk + Vite/Electron/TanStack Start/React RouterVITE_CLERK_PUBLISHABLE_KEYclientyes
Clerk + ExpoEXPO_PUBLIC_CLERK_PUBLISHABLE_KEYclientyes
WorkOSWORKOS_API_KEYserveryes
WorkOSWORKOS_COOKIE_PASSWORDserveryes
WorkOS + NextNEXT_PUBLIC_WORKOS_CLIENT_IDclientyes
WorkOS + AstroPUBLIC_WORKOS_CLIENT_IDclientyes
WorkOS + Vite/Electron/TanStack Start/React RouterVITE_WORKOS_CLIENT_IDclientyes
WorkOS + ExpoEXPO_PUBLIC_WORKOS_CLIENT_IDclientyes
ElectronVITE_DEV_SERVER_URLserverno (URL; injected in Electron dev)
StripeSTRIPE_SECRET_KEYserveryes
StripeSTRIPE_WEBHOOK_SECRETserveryes
StripeSTRIPE_PRICE_IDserveryes
StripeUPSTASH_REDIS_REST_URLserveryes (URL; Upstash Redis used as the Stripe KV store)
StripeUPSTASH_REDIS_REST_TOKENserveryes
PolarPOLAR_ACCESS_TOKENserveryes
PolarPOLAR_WEBHOOK_SECRETserveryes
PolarPOLAR_PRODUCT_IDserveryes
PolarPOLAR_SERVERserverno (sandbox | production; defaults to sandbox in code)
AutumnAUTUMN_SECRET_KEYserveryes
ResendRESEND_API_KEYserveryes
ResendEMAIL_FROMserveryes (Name <address@yourdomain.com>)

Better Auth extra secrets (for example GITHUB_CLIENT_ID) are not generated. Add them to the schema and .env.example if you need them.

Skipping validation ​

Validation is skipped when any of these is true:

  • CI is set
  • SKIP_ENV_VALIDATION=true
  • npm_lifecycle_event is lint

Those names, plus NODE_ENV, VERCEL, VERCEL_ENV, and VERCEL_URL, are listed on Turbo globalPassThroughEnv. Generated app/auth/db keys (except NODE_ENV) are listed on globalEnv.