Configuration25-40 min
Environment Validation with Zod
This guide creates a typed env module, validates required variables, separates server and client config, and wires validation into builds.
TypeScriptZodNode.js
Prerequisites
- A TypeScript project.
- Environment variables loaded by your runtime or hosting provider.
- A list of required secrets and public config values.
1
Install Zod
Implementation snippet
npm install zod2
Create the env schema
Implementation snippet
import { z } from "zod";
const envSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
DATABASE_URL: z.string().url(),
JWT_ACCESS_SECRET: z.string().min(32),
STRIPE_SECRET_KEY: z.string().startsWith("sk_"),
APP_URL: z.string().url(),
});
export const env = envSchema.parse(process.env);3
Use the typed env object
- Import `env` wherever server config is needed.
- Stop reading `process.env` directly across the codebase.
- Let TypeScript autocomplete available config keys.
- Fail startup immediately when required config is missing.
Implementation snippet
import { env } from "./env";
app.listen(3000, () => {
console.log(`API running for ${env.NODE_ENV} at ${env.APP_URL}`);
});4
Separate public client env
Client-side variables are visible to users. Keep secrets server-only and expose only safe public values.
Implementation snippet
const clientEnvSchema = z.object({
VITE_APP_URL: z.string().url(),
VITE_PUBLIC_ANALYTICS_ID: z.string().optional(),
});
export const clientEnv = clientEnvSchema.parse(import.meta.env);5
Run validation before build
Implementation snippet
"scripts": {
"env:check": "tsx src/env.ts",
"prebuild": "npm run env:check",
"build": "vite build"
}6
Verification checklist
Checklist
- Removing DATABASE_URL causes startup or build to fail.
- Invalid URL values produce readable Zod errors.
- Client env does not include private keys.
- Production hosting has every required variable configured.