AceDevHub
Production TypeScriptFree

Runtime Validation with Zod

Bridge compile-time types and runtime checks — parse unknown input, infer types from schemas, and fail safely at API boundaries.

AdvancedFreeValidation

TypeScript types erase at runtime — tsc cannot stop malformed JSON from crashing your handler. Zod defines schemas that validate at runtime and infer static types from the same definition. One schema serves parse, validate, and type inference — no drift between interface and validator.

Use Zod at trust boundaries: HTTP request bodies, webhook payloads, environment variables, and JSON.parse results. Internal function calls between typed modules rarely need runtime validation — external input always does.

Defining schemas

z.object, z.string, z.number, z.boolean compose like TypeScript shapes. .optional(), .nullable(), and .default() mirror optional fields. z.enum replaces string literal unions with runtime membership checks.

schema-basic.ts
Loading editor…

parse vs safeParse

parse throws ZodError on failure — fine when invalid input is exceptional. safeParse returns { success: true, data } | { success: false, error } — preferred for HTTP handlers returning 400 with field errors instead of 500 stack traces.

parse-safe.ts
Loading editor…
Outputconsole
{ email: ['Invalid email'], id: ['Invalid uuid'] }

Transform and refine

z.coerce.number converts string query params to numbers. .refine adds custom validation — password confirmation matching, cross-field rules. .transform maps validated input to domain types after parsing.

transform.ts
Loading editor…

API boundary pattern

Handlers receive unknown, safeParse once, return 400 on failure, proceed with typed data on success. Share schemas in packages/shared so frontend and backend validate the same shape — optional but powerful for form and API parity.

handler-pattern.ts
Loading editor…
MethodOn failure
parsethrows ZodError
safeParsereturns success: false
parseAsyncasync throw
safeParseAsyncasync Result
  • Zod validates what types cannot at runtime
  • z.infer keeps types synced
  • safeParse for user-facing errors
  1. 1Schema defines runtime + static shape
  2. 2safeParse at HTTP boundaries
  3. 3Share schemas in monorepos
  4. 4Next: migrating JavaScript to TypeScript