How to Secure Environment Variables
Environment variables are the standard way to manage secrets in modern applications, but they come with pitfalls. Accidentally committing .env files, using client-side prefixes for secrets, and leaking values in logs are common mistakes. This guide covers proper environment variable management across frameworks and platforms.
Find security issues automatically before attackers do.
Follow These Steps
Set up .gitignore before creating .env files
Add .env patterns to .gitignore before creating any environment files.
# .gitignore - add these BEFORE creating .env files
.env
.env.local
.env.production
.env.*.local
!.env.exampleIf .env was already committed, it is in git history. Add to .gitignore, run git rm --cached .env, and rotate all keys.
Create a .env.example with placeholder values
Provide a template so developers know which variables are needed without exposing real values.
# .env.example (safe to commit)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
OPENAI_API_KEY=sk-proj-your-key-here
STRIPE_SECRET_KEY=sk-test-your-key-here
NEXTAUTH_SECRET=generate-with-openssl-rand-base64-32
NEXTAUTH_URL=http://localhost:3000Understand framework-specific client-side prefixes
Different frameworks use different prefixes to expose env vars to the browser. Never use these for secrets.
# Variables exposed to browser (NEVER use for secrets):
# Next.js: NEXT_PUBLIC_*
# Vite: VITE_*
# CRA: REACT_APP_*
# Nuxt: NUXT_PUBLIC_*
# Server-only (safe for secrets):
# Any variable WITHOUT the above prefixes
DATABASE_URL=... # Server only
API_SECRET=... # Server only
NEXT_PUBLIC_URL=... # In browser bundle (not a secret)Validate environment variables at startup
Fail fast if required environment variables are missing.
import { z } from 'zod'
const envSchema = z.object({
DATABASE_URL: z.string().url(),
OPENAI_API_KEY: z.string().min(1),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
NODE_ENV: z.enum(['development', 'production', 'test'])
})
export const env = envSchema.parse(process.env)Configure secrets in your hosting platform
Add production secrets through the platform dashboard, not through committed files.
# Vercel: Settings > Environment Variables
# Netlify: Site settings > Environment variables
# Railway: Service > Variables tab
# Render: Service > Environment tab
# Replit: Secrets tab in sidebar
# Use different values for production vs preview/stagingPrevent secrets from appearing in logs
Sanitize environment variables from log output.
// Never log environment variables
console.log(process.env) // BAD - logs all secrets
// Log only non-sensitive values
console.log({
NODE_ENV: process.env.NODE_ENV,
PORT: process.env.PORT,
DATABASE_URL: '[REDACTED]'
})Set up a pre-commit hook to catch leaked secrets
Use gitleaks or similar to scan for secrets before every commit.
npm install -D husky
npx husky init
echo "npx gitleaks protect --staged --verbose" > .husky/pre-commitRotate secrets on a schedule
Regularly rotate API keys and secrets, especially after team member departures.
Set calendar reminders to rotate keys quarterly at minimum.
What You'll Achieve
Your environment variables are properly managed with .gitignore protection, validated at startup, framework-appropriate prefixing, platform-specific configuration, and pre-commit hooks to prevent leaks.
Common Mistakes to Avoid
Mistake
Using NEXT_PUBLIC_ or VITE_ prefix for secret API keys
Fix
These prefixes embed the variable in the client JavaScript bundle. Anyone can see them. Only use these for truly public values.
Mistake
Committing .env files to git
Fix
Add .env to .gitignore before creating the file. If already committed, remove with git rm --cached and rotate all keys.
Mistake
Using the same secrets for all environments
Fix
Use separate API keys for development, staging, and production. This limits blast radius if a non-production key is compromised.
Mistake
Logging process.env for debugging
Fix
This dumps all secrets to logs. Log only specific non-sensitive values and mark sensitive ones as [REDACTED].
Frequently Asked Questions
Are .env files secure?
.env files are only as secure as the machine they are on. They should never be committed to git. For production, always use your hosting platform's secrets manager instead of .env files.
Is it safe to commit .env.example?
Yes, as long as it contains only placeholder values, never real credentials. It serves as documentation for which variables are needed.
What if I accidentally committed a secret?
Rotate the secret immediately at the provider. Remove the file from git with git rm --cached, add to .gitignore, and commit. The old secret is still in git history, so rotation is essential.
Should I encrypt .env files?
For local development, .gitignore is sufficient. For production, use your hosting platform's encrypted secrets manager. Tools like dotenv-vault provide encrypted .env files for teams.
Ready to Secure Your App?
VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.
Start Security Scan