Environment Variables
Manage secrets and configuration across development, preview, and production environments on Vercel.
What you'll accomplish
Environment variables configured for all deployment environments
Prerequisites
- Project deployed to Vercel
Understanding Vercel Environments
Vercel has three deployment environments:
| Environment | When Used | URL Pattern |
|---|---|---|
| Production | main branch deploys | your-app.vercel.app |
| Preview | Other branches, PRs | your-app-git-branch.vercel.app |
| Development | Local with vercel dev | localhost:3000 |
Each can have different environment variable values.
┌─────────────────────────────────────────────────────────┐
│ Your Project │
├─────────────┬─────────────────┬───────────────────────┤
│ Development │ Preview │ Production │
├─────────────┼─────────────────┼───────────────────────┤
│ DB: local │ DB: staging │ DB: production │
│ API: mock │ API: staging │ API: production │
│ DEBUG: true │ DEBUG: true │ DEBUG: false │
└─────────────┴─────────────────┴───────────────────────┘
Adding Environment Variables
Via Dashboard (Recommended for Secrets)
- Go to your project in Vercel Dashboard
- Navigate to Settings → Environment Variables
- Click Add New
- Enter:
- Name: Variable name (e.g.,
DATABASE_URL) - Value: The secret value
- Environments: Select which environments need this value
- Name: Variable name (e.g.,
Via CLI
bash# Add interactively vercel env add DATABASE_URL # Prompts: # ? Which Environments? Production, Preview, Development # ? What's the value? postgresql://user:pass@host/db # Add to specific environment vercel env add API_KEY production
Via vercel.json (Non-Sensitive Only)
For values that aren't secrets:
json{ "env": { "NEXT_PUBLIC_SITE_URL": "https://example.com", "NODE_ENV": "production" } }
Note
Never put secrets in vercel.json - it's committed to Git! Use the dashboard or CLI for sensitive values.
Variable Naming
Client-Side vs Server-Side
For Next.js, variable names control where they're available:
| Prefix | Available In | Example |
|---|---|---|
NEXT_PUBLIC_ | Browser + Server | NEXT_PUBLIC_API_URL |
| (none) | Server only | DATABASE_URL |
javascript// Server-side (API routes, getServerSideProps) process.env.DATABASE_URL // ✓ Works // Client-side (React components) process.env.NEXT_PUBLIC_API_URL // ✓ Works process.env.DATABASE_URL // ✗ undefined
Note
Never prefix secrets with NEXT_PUBLIC_ - they'll be exposed in client-side JavaScript bundles!
Other Frameworks
| Framework | Client Prefix |
|---|---|
| Vite | VITE_ |
| Create React App | REACT_APP_ |
| Vue CLI | VUE_APP_ |
| Nuxt | NUXT_PUBLIC_ |
| SvelteKit | PUBLIC_ |
Environment-Specific Values
Same Variable, Different Values
You can set different values per environment:
DATABASE_URL:
├── Production: postgresql://prod-db.example.com/app
├── Preview: postgresql://staging-db.example.com/app
└── Development: postgresql://localhost/app_dev
Example Setup
Production variables:
DATABASE_URL=postgresql://prod-db.example.com/myapp
STRIPE_SECRET_KEY=sk_live_xxxxxxxx
NEXT_PUBLIC_API_URL=https://api.example.com
Preview variables:
DATABASE_URL=postgresql://staging-db.example.com/myapp
STRIPE_SECRET_KEY=sk_test_xxxxxxxx
NEXT_PUBLIC_API_URL=https://staging-api.example.com
Development variables:
DATABASE_URL=postgresql://localhost/myapp_dev
STRIPE_SECRET_KEY=sk_test_xxxxxxxx
NEXT_PUBLIC_API_URL=http://localhost:3001
Pulling Variables Locally
Pull to .env.local
bash# Pull all variables for development vercel env pull # Creates .env.local: # DATABASE_URL="postgresql://localhost/myapp_dev" # STRIPE_SECRET_KEY="sk_test_xxxxxxxx" # NEXT_PUBLIC_API_URL="http://localhost:3001"
Pull Specific Environment
bash# Pull production values vercel env pull --environment=production .env.production.local # Pull preview values vercel env pull --environment=preview .env.preview.local
.gitignore
Make sure to ignore local env files:
gitignore# .gitignore .env.local .env.development.local .env.production.local .env.preview.local
System Environment Variables
Vercel provides these automatically:
| Variable | Description |
|---|---|
VERCEL | "1" when running on Vercel |
VERCEL_ENV | production, preview, or development |
VERCEL_URL | Deployment URL (without protocol) |
VERCEL_BRANCH_URL | Branch-specific URL |
VERCEL_GIT_COMMIT_SHA | Git commit hash |
VERCEL_GIT_COMMIT_MESSAGE | Commit message |
VERCEL_GIT_COMMIT_AUTHOR_NAME | Commit author |
VERCEL_GIT_REPO_SLUG | Repository name |
VERCEL_GIT_REPO_OWNER | Repository owner |
VERCEL_GIT_PROVIDER | github, gitlab, or bitbucket |
Using System Variables
javascript// Detect if running on Vercel if (process.env.VERCEL) { console.log('Running on Vercel'); } // Get current environment const isProduction = process.env.VERCEL_ENV === 'production'; // Construct URL const url = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000';
Sensitive vs Plain Text
Sensitive (Encrypted)
Choose "Sensitive" for:
- API keys
- Database passwords
- Authentication secrets
- Private keys
Sensitive values are:
- Encrypted at rest
- Hidden in UI after creation
- Can only be viewed via CLI or recreated
Plain Text
Choose "Plain" for:
- Public URLs
- Feature flags
- Configuration values
- Non-secret settings
Referencing Other Variables
You can reference other variables:
bash# In dashboard or CLI, use ${} BASE_URL=https://api.example.com API_ENDPOINT=${BASE_URL}/v1 # Result: API_ENDPOINT = "https://api.example.com/v1"
Build vs Runtime
Build-Time Variables
Available during npm run build:
- Used for static generation
- Baked into the build
- Changing requires rebuild
Runtime Variables
Available when functions execute:
- Fresh on each request
- Can be updated without rebuild
- Only for server-side code
Note
All variables are available at build time. But NEXT_PUBLIC_ variables are baked in - you can't change them without rebuilding.
Managing Variables
List All Variables
bashvercel env ls # Output: # ┌──────────────────────┬────────────────┬─────────────────────┐ # │ Name │ Value │ Environments │ # ├──────────────────────┼────────────────┼─────────────────────┤ # │ DATABASE_URL │ ●●●●●●●●●●● │ All │ # │ NEXT_PUBLIC_API_URL │ https://... │ Production │ # │ DEBUG │ true │ Preview, Dev │ # └──────────────────────┴────────────────┴─────────────────────┘
Remove Variable
bash# Remove from all environments vercel env rm DATABASE_URL # Remove from specific environment vercel env rm DATABASE_URL production
Troubleshooting
Variable Not Available
- Check environment selection - Is it set for Production/Preview/Development?
- Check the prefix - Client-side needs
NEXT_PUBLIC_ - Redeploy - Changes require a new deployment
- Check spelling - Variable names are case-sensitive
Debugging
javascript// Log all available env vars (development only!) console.log('Environment:', process.env.VERCEL_ENV); console.log('Available vars:', Object.keys(process.env).filter(k => k.startsWith('NEXT_PUBLIC_')));
Common Mistakes
| Problem | Solution |
|---|---|
| Variable undefined in browser | Add NEXT_PUBLIC_ prefix |
| Secret showing in client | Remove NEXT_PUBLIC_ prefix |
| Different value than expected | Check environment (prod vs preview) |
| Changes not applying | Trigger new deployment |
Security Best Practices
- Never log secrets - Even in development
- Rotate regularly - Especially API keys
- Minimal access - Only add to needed environments
- Use Sensitive type - For anything confidential
- Review periodically - Remove unused variables
Note
Checkpoint: Set up environment variables for Production and Preview environments, then run vercel env pull to get them locally.