Node.js cookbook · Beginner
Validate environment configuration at startup
Fail fast with a clear message when an env variable is missing or malformed, and get typed config.
Approach
Parse process.env once with a Zod schema at startup, coerce types (numbers, booleans, URLs), provide defaults, and export a frozen, typed config object. Never read process.env elsewhere. Node 20.6+ can load .env files natively with --env-file.
Solution
// src/config.ts
import { z } from "zod";
const Env = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().min(1).max(65535).default(3000),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
JWT_AUDIENCE: z.string().min(1),
CORS_ORIGINS: z.string().transform((s) => s.split(",").map((o) => o.trim())).default(""),
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
});
const parsed = Env.safeParse(process.env);
if (!parsed.success) {
console.error("Invalid configuration:", parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const config = Object.freeze(parsed.data);
export type Config = typeof config;
node --env-file=.env dist/server.js # Node 20.6+ loads .env natively
Pitfalls
process.env.PORTused as a string number.- Logging the config object with secrets.
- Defaults for secrets (fail instead).
Variations
@t3-oss/env-corefor client/server env separation in full-stack apps.
Further reading: Node.js: --env-file
Reference: https://nodejs.org/api/cli.html#--env-fileconfig
More Node.js recipes
- Add health and readiness endpoints to a Node.js service
- Add JWT authentication to an Express API
- Cache expensive lookups in Redis from Node.js
- Call external APIs with timeouts and retries in Node.js
- Centralize error handling in Express 5
- Hash passwords and implement login safely in Node.js
- Implement cursor pagination with PostgreSQL in Node.js
- Offload CPU-heavy work with worker threads