Step-by-Step Guide
8 steps

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

1

Set up .gitignore before creating .env files

Add .env patterns to .gitignore before creating any environment files.

Code Example
# .gitignore - add these BEFORE creating .env files
.env
.env.local
.env.production
.env.*.local
!.env.example

If .env was already committed, it is in git history. Add to .gitignore, run git rm --cached .env, and rotate all keys.

2

Create a .env.example with placeholder values

Provide a template so developers know which variables are needed without exposing real values.

Code Example
# .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:3000
3

Understand framework-specific client-side prefixes

Different frameworks use different prefixes to expose env vars to the browser. Never use these for secrets.

Code Example
# 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)
4

Validate environment variables at startup

Fail fast if required environment variables are missing.

Code Example
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)
5

Configure secrets in your hosting platform

Add production secrets through the platform dashboard, not through committed files.

Code Example
# 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/staging
6

Prevent secrets from appearing in logs

Sanitize environment variables from log output.

Code Example
// 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]'
})
7

Set up a pre-commit hook to catch leaked secrets

Use gitleaks or similar to scan for secrets before every commit.

Code Example
npm install -D husky
npx husky init
echo "npx gitleaks protect --staged --verbose" > .husky/pre-commit
8

Rotate 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