Overview

Vercel stores environment variables encrypted at rest and injects them at build time or at function runtime. Mis-scoped variables cause two recurring failures: preview deployments that touch production data, and builds that fail because a variable is missing. Give each variable only the environments that need it, use the Secret type for credentials, and redeploy after every change. General secret hygiene (git, scanning, client prefixes) is on secrets-and-env.

Give each variable only the environments that need it

Choose any of Production, Preview, Development, and custom environments per variable. Preview variables can also be limited to one Git branch, and a branch-specific value overrides the general Preview one.

VariableDevelopmentPreviewProduction
DATABASE_URLlocalstagingproduction
STRIPE_SECRET_KEYtest keytest keylive key
NEXT_PUBLIC_API_URLhttp://localhost:3001preview APIproduction API

Never give Preview the production DATABASE_URL: a bad migration or test write from an unmerged branch would hit production (vercel-preview-deployments).

Use the Secret type for credentials

Since August 2026 variables have two types: Config (value stays readable to project members) and Secret (the value can be replaced but never viewed or retrieved). Variables previously marked Sensitive became Secrets with no migration. On the CLI, --visibility secret or --visibility config sets the type, and the legacy --sensitive and --no-sensitive flags still map to Secret and Config (changelog). A team policy, “Separate Production Secret Values”, requires Production secrets to differ from other environments; the older “Enforce Sensitive Environment Variables” policy is deprecated.

Make these Secrets: API keys, database URLs with credentials, JWT signing secrets, OAuth client secrets. Public values (API base URL, analytics ID) can stay Config. Secret type limits viewing; it does not replace access control on who can edit variables.

Redeploy after every change

Changes apply only to new deployments; existing ones keep the old values. After editing a variable, trigger a new deployment before assuming it took effect.

Keep NEXT_PUBLIC_ values free of secrets

Next.js inlines NEXT_PUBLIC_* variables into the browser bundle at build time, so any value with that prefix is public. Variables without it are available only in server code. Details: nextjs and secrets-and-env.

Stay under the size limits

Variables on Node.js, Python, Ruby, Go, and the PHP community runtime may total 64 KB per deployment (no single variable above 64 KB). Edge runtime functions and Middleware with the edge runtime cap each variable at 5 KB (docs). Store large certificates or JWKS as files fetched at runtime if either limit is a problem.

Pull and add variables with the CLI

vercel env pull .env.local                       # writes Development-scoped values
vercel env add DATABASE_URL production --visibility secret
vercel env add STRIPE_TEST_KEY preview development
vercel env ls                                    # names, not values

Add .env.local to .gitignore and re-pull when a variable changes; local drift from the Development scope causes “works locally, fails on preview”. If you manage variables with Terraform, remember values land in Terraform state, which must itself be encrypted and access-controlled.

Rotate secrets with overlapping credentials

  1. Create the new credential upstream.
  2. Update the Vercel variable.
  3. Deploy and confirm the new deployment works.
  4. Revoke the old credential.

Deployments are immutable, so the live deployment keeps the old value until the new one is promoted. Revoking first causes an outage if the deploy is slow.