Deploy Next.js 15 to Vercel Without Environment Variable
Environment variables not working on Vercel? Learn the exact configuration needed for Next.js 15 deployment with zero errors.
Deploy Next.js 15 to Vercel Without Environment Variable#
Deploy Next.js 15 to Vercel Without Environment Variable Errors#
Environment variable errors are the #1 cause of failed Vercel deployments. Your app works locally, but in production you get "undefined" errors, API calls fail, or the build crashes. This guide covers everything you need to know about environment variables in Next.js 15 and Vercel.
This article is part of our comprehensive Deploying Next.js + Supabase to Production guide.
Understanding Environment Variables in Next.js#
Next.js has specific rules for environment variables:
- NEXT_PUBLIC_* - Exposed to browser (client-side)
- Regular variables - Server-side only
- Build-time - Bundled during build
- Runtime - Loaded when server starts
Common Error Messages#
## Error 1: Undefined variable
ReferenceError: process is not defined
## Error 2: Variable not found
Error: NEXT_PUBLIC_API_URL is not defined
## Error 3: Build failure
Error: Environment variable DATABASE_URL is required
## Error 4: Wrong value in production
API_URL: undefined (expected: https://api.example.com)
Solution 1: Understand NEXT_PUBLIC_ Prefix#
The most important rule:
Client-Side Variables MUST Have NEXT_PUBLIC_#
## .env.local
## ❌ WRONG: Won't work in browser
API_URL=https://api.example.com
## ✅ CORRECT: Accessible in browser
NEXT_PUBLIC_API_URL=https://api.example.com
## ✅ CORRECT: Server-only (no prefix needed)
DATABASE_URL=postgresql://...
API_SECRET_KEY=secret123
Usage in Code#
// ❌ BAD: Won't work in client components
'use client'
export function ApiClient() {
const apiUrl = process.env.API_URL // ❌ undefined in browser
return <div>{apiUrl}</div>
}
// ✅ GOOD: Use NEXT_PUBLIC_ prefix
'use client'
export function ApiClient() {
const apiUrl = process.env.NEXT_PUBLIC_API_URL // ✅ Works!
return <div>{apiUrl}</div>
}
// ✅ GOOD: Server-only variables in Server Components
export async function ServerComponent() {
const dbUrl = process.env.DATABASE_URL // ✅ Works (server-side)
// Use dbUrl for database connection
}
Solution 2: Configure Vercel Environment Variables#
Step-by-step Vercel configuration:
Add Variables in Vercel Dashboard#
## 1. Go to: Vercel Dashboard > Your Project > Settings > Environment Variables
## 2. Add each variable:
Name: NEXT_PUBLIC_SUPABASE_URL
Value: https://your-project.supabase.co
Environment: Production, Preview, Development
Name: NEXT_PUBLIC_SUPABASE_ANON_KEY
Value: your-anon-key
Environment: Production, Preview, Development
Name: DATABASE_URL
Value: postgresql://...
Environment: Production (server-only, don't expose)
## 3. Click "Save"
## 4. Redeploy your application
Environment-Specific Variables#
## Production only
NEXT_PUBLIC_API_URL=https://api.production.com
DATABASE_URL=postgresql://prod-db
## Preview (branch deployments)
NEXT_PUBLIC_API_URL=https://api.staging.com
DATABASE_URL=postgresql://staging-db
## Development (local)
NEXT_PUBLIC_API_URL=http://localhost:3000
DATABASE_URL=postgresql://localhost:5432
Solution 3: Use .env Files Correctly#
Local development setup:
File Priority Order#
## Next.js loads env files in this order (later overrides earlier):
1. .env # All environments
2. .env.local # Local overrides (gitignored)
3. .env.development # Development only
4. .env.development.local # Local dev overrides
5. .env.production # Production only
6. .env.production.local # Local prod overrides
Example .env Files#
## .env (committed to git)
NEXT_PUBLIC_APP_NAME=My App
NEXT_PUBLIC_API_VERSION=v1
## .env.local (gitignored - your local secrets)
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-key
DATABASE_URL=postgresql://localhost:5432/mydb
## .env.production (committed - production defaults)
NEXT_PUBLIC_API_URL=https://api.production.com
NODE_ENV=production
.gitignore Configuration#
## .gitignore
.env*.local
.env.local
.env.development.local
.env.test.local
.env.production.local
Solution 4: Handle Build-Time vs Runtime#
Critical difference:
Build-Time Variables#
// These are bundled at BUILD time
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// If you change the variable after build, it won't update!
// You must rebuild the application
Runtime Variables (Server-Only)#
// Server-side variables are loaded at RUNTIME
export async function GET() {
const dbUrl = process.env.DATABASE_URL // ✅ Loaded at runtime
// Connect to database
}
Solution: Use Runtime Configuration#
// next.config.mjs
const nextConfig = {
// For runtime environment variables
serverRuntimeConfig: {
// Server-side only
databaseUrl: process.env.DATABASE_URL,
},
publicRuntimeConfig: {
// Available on both server and client
apiUrl: process.env.NEXT_PUBLIC_API_URL,
},
}
// Usage
import getConfig from 'next/config'
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
const { databaseUrl } = serverRuntimeConfig
const { apiUrl } = publicRuntimeConfig
Solution 5: Validate Environment Variables#
Catch missing variables early:
Create Validation Schema#
// lib/env.ts
import { z } from 'zod'
const envSchema = z.object({
// Client-side (NEXT_PUBLIC_)
NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
NEXT_PUBLIC_SUPABASE_ANON_KEY: z.string().min(1),
NEXT_PUBLIC_API_URL: z.string().url(),
// Server-side
DATABASE_URL: z.string().url(),
API_SECRET_KEY: z.string().min(32),
SMTP_HOST: z.string().optional(),
})
export const env = envSchema.parse({
NEXT_PUBLIC_SUPABASE_URL: process.env.NEXT_PUBLIC_SUPABASE_URL,
NEXT_PUBLIC_SUPABASE_ANON_KEY: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
DATABASE_URL: process.env.DATABASE_URL,
API_SECRET_KEY: process.env.API_SECRET_KEY,
SMTP_HOST: process.env.SMTP_HOST,
})
// Usage
import { env } from '@/lib/env'
const apiUrl = env.NEXT_PUBLIC_API_URL // ✅ Type-safe and validated
Build-Time Validation#
// scripts/validate-env.js
const requiredEnvVars = [
'NEXT_PUBLIC_SUPABASE_URL',
'NEXT_PUBLIC_SUPABASE_ANON_KEY',
'DATABASE_URL',
]
const missing = requiredEnvVars.filter(key => !process.env[key])
if (missing.length > 0) {
console.error('Missing required environment variables:')
missing.forEach(key => console.error(` - ${key}`))
process.exit(1)
}
console.log('✅ All required environment variables are set')
// package.json
{
"scripts": {
"validate-env": "node scripts/validate-env.js",
"build": "npm run validate-env && next build"
}
}
Solution 6: Use Vercel CLI for Testing#
Test locally with production environment:
Install Vercel CLI#
npm install -g vercel
## Login
vercel login
## Link project
vercel link
Pull Environment Variables#
## Download production env vars to .env.local
vercel env pull .env.local
## Now your local environment matches production
npm run dev
Test Production Build#
## Build with production env vars
vercel build
## Test production build locally
vercel dev --prod
Solution 7: Handle Different Environments#
Manage multiple environments:
Environment-Specific Configuration#
// lib/config.ts
const config = {
development: {
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000',
debug: true,
},
production: {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
debug: false,
},
preview: {
apiUrl: process.env.NEXT_PUBLIC_API_URL,
debug: true,
},
}
const env = process.env.NODE_ENV || 'development'
export default config[env]
Vercel Environment Detection#
// Detect Vercel environment
const isProduction = process.env.VERCEL_ENV === 'production'
const isPreview = process.env.VERCEL_ENV === 'preview'
const isDevelopment = process.env.VERCEL_ENV === 'development'
// Use Vercel URL
const vercelUrl = process.env.VERCEL_URL
const siteUrl = isProduction
? 'https://iloveblog.blog'
: `https://${vercelUrl}`
Common Mistakes#
-
Mistake #1: Forgetting NEXT_PUBLIC_ prefix - Client-side variables must have this prefix
-
Mistake #2: Not redeploying after adding variables - Vercel needs redeploy to pick up new variables
-
Mistake #3: Committing .env.local - This file should be gitignored
-
Mistake #4: Using wrong environment - Check which environment (Production/Preview/Development) you're configuring
-
Mistake #5: Exposing secrets - Never use NEXT_PUBLIC_ for sensitive data
FAQ#
Why are my environment variables undefined in production?#
Either they're not configured in Vercel dashboard, or you forgot the NEXT_PUBLIC_ prefix for client-side variables. Check both.
Do I need to redeploy after adding environment variables?#
Yes! Vercel doesn't automatically redeploy. Go to Deployments > Latest > Redeploy.
Can I use environment variables in next.config.js?#
Yes, but they must be available at build time. Use process.env.VARIABLE_NAME.
How do I hide sensitive data from the client?#
Don't use NEXT_PUBLIC_ prefix. Keep sensitive variables server-side only (API routes, Server Components).
Why do variables work locally but not on Vercel?#
Local variables are in .env.local (gitignored). You must add them to Vercel dashboard separately.
Related Articles#
- Next.js Turbopack Stuck on Compiling How to Fix
- Fix Next.js Build Error Module Not Found After Deploy
- Resolve Next.js Hydration Mismatch Errors Complete Guide
- Deploying Next.js + Supabase to Production
Conclusion#
Environment variable errors on Vercel are usually caused by missing NEXT_PUBLIC_ prefix for client-side variables, or forgetting to configure variables in the Vercel dashboard. The key rules are:
- Use NEXT_PUBLIC_ prefix for browser-accessible variables
- Configure all variables in Vercel dashboard
- Redeploy after adding/changing variables
- Never commit .env.local to git
- Validate environment variables at build time
Use the Vercel CLI to pull production environment variables locally for testing. Always validate required variables before deployment to catch issues early.
Remember: NEXT_PUBLIC_ variables are bundled into your JavaScript and visible to users. Never use this prefix for secrets, API keys, or sensitive data.
Frequently Asked Questions
Continue Reading
Fix Next.js Build Error Module Not Found After Deploy
Module not found errors only in production? Learn why Next.js builds fail after deploy and get 6 proven fixes that work on Vercel, AWS, and other platforms.
Next.js 15 vs Next.js 14: Performance Comparison and Migration Guide 2026
Comprehensive comparison of Next.js 15 and 14 performance improvements, new features, breaking changes, and whether you should upgrade your production app.
Resolve Next.js Hydration Mismatch Errors Complete Guide
Hydration mismatch errors breaking your Next.js app? Learn the root causes and 8 proven fixes to eliminate these errors permanently.
Browse by Topic
Find stories that matter to you.