Topic 5 of 55
Environment Variables
Overview
Environment variables keep secrets (API keys, DB passwords) out of source code and allow different configurations for development, staging, and production without code changes. They are a security and deployment necessity.
Syntax
bash
# .env (never commit to git!)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
JWT_SECRET=your-secret-key-here
STRIPE_SECRET_KEY=sk_test_...
PORT=3000
NODE_ENV=development
# .env.example (commit this — shows required variables)
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
JWT_SECRET=your-jwt-secret
STRIPE_SECRET_KEY=sk_test_or_live_key
// Loading with dotenv
import 'dotenv/config'; // loads .env automatically
const port = process.env.PORT ?? 3000;
const isDev = process.env.NODE_ENV === 'development';Common Pitfalls
- Never commit .env files — add them to .gitignore. Leaked secrets are a major security incident.
- process.env values are always strings — numbers and booleans need parsing (parseInt, === 'true').
- Interview tip: The 12-Factor App methodology says config should come from environment variables, not files — enables containerized deployments.
Real-World Example
A type-safe configuration module with validation:
example
bash
// config/index.ts
import { z } from 'zod';
const EnvSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
JWT_EXPIRES_IN: z.string().default('7d'),
REDIS_URL: z.string().url().optional(),
SMTP_HOST: z.string(),
SMTP_PORT: z.coerce.number().default(587),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
RAZORPAY_KEY_ID: z.string(),
});
// Validate at startup — fail fast if config is wrong
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error('❌ Invalid environment variables:');
console.error(parsed.error.flatten().fieldErrors);
process.exit(1); // don't start with bad config!
}
export const config = parsed.data;
export const isDev = config.NODE_ENV === 'development';
export const isProd = config.NODE_ENV === 'production';