DEV Community

Young Gao
Young Gao

Posted on

Environment Variables Done Right: Stop Hardcoding Secrets in 2026

Your .env file is in git. Your database password is in plain text. Your JWT secret is the same in dev and prod.

The Basics

import { z } from "zod";
const envSchema = z.object({
  DATABASE_URL: z.string().url(),
  JWT_SECRET: z.string().min(32),
  PORT: z.coerce.number().default(3000),
  NODE_ENV: z.enum(["development", "production", "test"]),
});
export const env = envSchema.parse(process.env);
Enter fullscreen mode Exit fullscreen mode

App crashes at startup if any env var is missing or wrong type. No more runtime surprises.

Secret Management in Production

Never store secrets in .env files in production. Options:

  1. Cloud provider secrets: AWS Secrets Manager, GCP Secret Manager, Azure Key Vault
  2. HashiCorp Vault: Self-hosted, dynamic secrets, auto-rotation
  3. Kubernetes secrets: Base64 encoded (not encrypted), use sealed-secrets or external-secrets operator

.gitignore Rules

.env
.env.local
.env.production
Enter fullscreen mode Exit fullscreen mode

Commit .env.example with placeholder values. Never commit actual secrets.

Secret Rotation

Rotate secrets without downtime: support TWO valid secrets simultaneously during rotation. Accept both old and new JWT secrets during a transition window.


Part of my Production Backend Patterns series. Follow for more practical backend engineering.


If this was useful, consider:


You Might Also Like

Follow me for more production-ready backend content!


If this helped you, buy me a coffee on Ko-fi!

Top comments (0)