Next.js Environment Variables: Complete Security Guide 2025
Environment variables in Next.js applications handle everything from API keys to database URLs, making their security critical for production applications. Mishandling these variables can expose sensitive data to client browsers, leak secrets in build logs, or create vulnerabilities that compromise your entire application.
This guide covers the complete security model for Next.js environment variables, including the crucial differences between client and server-side variables, Vercel deployment best practices, and the security pitfalls that can expose your secrets to the world.
Understanding Next.js Environment Variable Types
Next.js handles environment variables differently depending on where they're accessed. Server-side variables remain secure on your server, while client-side variables get bundled into your JavaScript and become visible to anyone.
Server-Side Environment Variables
Server-side variables are accessible in API routes, server components, and build-time processes. These variables never reach the browser and remain secure on your server infrastructure.
// API route - server-side only
export default function handler(req, res) {
const databaseUrl = process.env.DATABASE_URL; // Secure
const apiSecret = process.env.API_SECRET_KEY; // Secure
// These variables never reach the client
}
Server-side variables include database connection strings, API secrets, webhook signing keys, and any sensitive configuration that should never be exposed publicly.
Client-Side Environment Variables
Client-side variables must be prefixed with NEXT_PUBLIC_ and become part of your JavaScript bundle. Anyone can inspect these values through browser developer tools or by examining your built JavaScript files.
// Client component - publicly visible
export default function Component() {
const publicApiUrl = process.env.NEXT_PUBLIC_API_URL; // Visible to everyone
const analyticsId = process.env.NEXT_PUBLIC_ANALYTICS_ID; // Public
return <div>Component content</div>;
}
Only use NEXT_PUBLIC_ variables for truly public configuration like API endpoints, feature flags, or analytics tracking IDs that don't compromise security when exposed.
Setting Up Secure Environment Variables
Proper environment variable setup prevents accidental exposure and ensures your secrets remain protected across all environments.
Local Development Setup
Create separate .env files for different environments. Next.js loads these files in a specific order, with .env.local taking precedence for local development.
# .env.local (never commit to git)
DATABASE_URL="postgresql://user:password@localhost:5432/myapp"
NEXTAUTH_SECRET="your-local-secret-key"
STRIPE_SECRET_KEY="sk_test_..."
# .env (can commit - only non-sensitive defaults)
NEXT_PUBLIC_APP_NAME="MyApp"
NEXT_PUBLIC_API_URL="http://localhost:3000/api"
Add .env.local to your .gitignore file to prevent accidental commits of sensitive data. Your .env file can contain non-sensitive defaults that work for all developers.
Production Environment Configuration
Production environments require different values and additional security measures. Never use the same secrets across environments, and implement proper access controls for production variables.
# Production .env (deployed securely)
DATABASE_URL="postgresql://prod-user:complex-password@prod-db:5432/myapp"
NEXTAUTH_SECRET="production-secret-with-high-entropy"
STRIPE_SECRET_KEY="sk_live_..."
# Public production variables
NEXT_PUBLIC_API_URL="https://myapp.com/api"
NEXT_PUBLIC_ANALYTICS_ID="G-XXXXXXXXXX"
Rotate production secrets regularly and use different values for staging and production environments to limit blast radius if credentials are compromised.
Vercel Environment Variable Management
Vercel provides built-in environment variable management with security features like encrypted storage and environment-specific deployment.
Setting Variables in Vercel Dashboard
Access your project settings in the Vercel dashboard and navigate to the Environment Variables section. Vercel encrypts all environment variables and provides granular control over which environments can access specific variables.
Set variables for specific environments (Development, Preview, Production) to ensure staging deployments don't accidentally use production credentials. Use Vercel's "Sensitive" checkbox for secrets to prevent them from appearing in build logs.
Vercel CLI Environment Management
The Vercel CLI allows programmatic environment variable management for teams and automation workflows.
# Add environment variable via CLI
vercel env add DATABASE_URL production
# Pull environment variables for local development
vercel env pull .env.local
# List all environment variables
vercel env ls
Use the CLI for team workflows where multiple developers need consistent environment setups, but be careful not to expose secrets in shell history or CI logs.
Environment Variable Inheritance
Vercel supports environment variable inheritance across deployments. Preview deployments can inherit production variables while overriding specific values for testing.
Configure inheritance carefully to prevent preview branches from accidentally using production databases or sending real emails during testing.
Common Security Pitfalls and How to Avoid Them
Environment variable security failures often stem from misunderstanding Next.js variable scoping or improper deployment practices.
Accidentally Exposing Server Variables to Client
The most dangerous mistake is trying to access server-side environment variables in client components. This fails silently and can lead to undefined behavior or security vulnerabilities.
// WRONG - This exposes nothing but creates confusion
export default function ClientComponent() {
const secret = process.env.API_SECRET; // undefined in browser
// Developer might add NEXT_PUBLIC_ prefix, exposing the secret
}
// CORRECT - Pass data through props or API calls
export default function ClientComponent({ publicData }) {
// Receive processed data that's safe to display
}
When client components need server data, fetch it through API routes that can securely access environment variables and return only the necessary public information.
Build-Time Variable Exposure
Next.js evaluates some environment variables at build time, potentially exposing them in build artifacts or logs. Be especially careful with variables used in next.config.js or during static generation.
// next.config.js - Variables here become part of build output
module.exports = {
env: {
// Only put truly public values here
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
// Use runtime configuration for sensitive values
serverRuntimeConfig: {
mySecret: process.env.MY_SECRET, // Server-only at runtime
},
};
Use Next.js runtime configuration for sensitive values that shouldn't be embedded in build artifacts.
Logging and Error Exposure
Environment variables can accidentally appear in application logs, error messages, or debugging output. Implement proper error handling and logging practices to prevent secret leakage.
// WRONG - Might log sensitive data
console.log('Database connection failed:', process.env.DATABASE_URL);
// CORRECT - Log without exposing secrets
console.log('Database connection failed to host:', new URL(process.env.DATABASE_URL).hostname);
Configure your logging infrastructure to automatically redact common secret patterns and avoid logging full environment variable values.
Secret Rotation and Management
Regular secret rotation limits the impact of compromised credentials and maintains security hygiene across your application lifecycle.
Implementing Secret Rotation
Design your application to handle secret rotation gracefully. Use connection pooling and graceful shutdowns to minimize disruption when rotating database credentials or API keys.
// API route with rotation-friendly design
export default async function handler(req, res) {
try {
const apiKey = process.env.EXTERNAL_API_KEY;
const response = await fetch('https://api.example.com/data', {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
if (response.status === 401) {
// Log rotation needed, don't expose the key
console.log('API authentication failed - key rotation may be needed');
}
return res.json(await response.json());
} catch (error) {
// Handle errors without exposing secrets
return res.status(500).json({ error: 'External API unavailable' });
}
}
Implement monitoring and alerting for authentication failures that might indicate compromised or expired credentials.
Automated Secret Management
For production applications, consider integrating with secret management services like AWS Secrets Manager, HashiCorp Vault, or Vercel's upcoming secret management features.
These services provide automated rotation, audit logging, and fine-grained access controls that surpass basic environment variable security. When implementing Claude Code production deployment, proper secret management becomes even more critical for maintaining security across automated deployments.
Environment Variable Validation
Validate environment variables at application startup to catch configuration errors before they cause runtime failures or security issues.
// lib/env-validation.js
function validateEnvironment() {
const required = ['DATABASE_URL', 'NEXTAUTH_SECRET'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
// Validate format without logging values
if (!process.env.DATABASE_URL.startsWith('postgresql://')) {
throw new Error('DATABASE_URL must be a valid PostgreSQL connection string');
}
}
// Call during app initialization
validateEnvironment();
Implement validation that checks for required variables and basic format requirements without logging the actual values.
Next Steps
With proper environment variable security in place, focus on implementing comprehensive authentication and authorization. The Next.js Middleware Authentication guide covers protecting your routes and API endpoints.
For teams building MVPs quickly, review technical debt considerations to understand which security measures are essential from day one versus what can be improved iteratively.
Regular security audits of your environment variable usage, combined with automated secret rotation and proper access controls, create a robust foundation for secure Next.js applications in production.