Build a Typed REST API with Express, TypeScript & Zod

Lesson 6 of 8

Environment Variables & Configuration with Zod

process.env is where an Express app's real configuration lives, database URLs, API keys, ports, but TypeScript types every property on process.env as string | undefined, and nothing stops a typo'd or missing variable from reaching production. Validate it with Zod the same way you validate a request body.

TypeScript

z.coerce.number() converts the incoming string (everything in process.env is a string) to a number before validating it, exactly what an environment variable needs, PORT arrives as the string "3000", not the number 3000. Calling EnvSchema.parse(process.env) once, at startup, means a missing or malformed DATABASE_URL crashes the app immediately with a clear error, instead of failing mysteriously the first time a database query runs, minutes or hours later.

A typed config module

TypeScript
TypeScript

Importing config instead of reading process.env directly anywhere else in the codebase means every other file gets a fully typed, already-validated object, no string | undefined and no repeated validation.

WARNING

Never commit real secrets (database passwords, API keys) to source control, even in a .env.example file, real .env files belong in .gitignore. Zod validates the shape of your configuration, it doesn't protect a secret that's already been checked in.

📝 Environment Config Quiz

Passing score: 70%
  1. 1.Why use z.coerce.number() for an environment variable like PORT?

  2. 2.Every property on process.env is typed as string | undefined by TypeScript, without extra validation.

  3. 3.Calling EnvSchema.parse(process.env) once at ____ crashes the app immediately on bad config instead of failing later.