Zod
Version 1.0.0
community
January 2026
Note:
This document is mainly for agents and LLMs to follow when maintaining,
generating, or refactoring codebases. Humans may also find it useful,
but guidance here is optimized for automation and consistency by AI-assisted workflows.
Abstract
Comprehensive schema validation guide for Zod in TypeScript applications, designed for AI agents and LLMs. Contains 43 rules across 8 categories, prioritized by impact from critical (schema definition, parsing) to incremental (performance, bundle optimization). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.
Table of Contents
- Schema Definition — CRITICAL
- 1.1 Apply String Validations at Schema Definition — CRITICAL (Unvalidated strings allow SQL injection, XSS, and malformed data; validating at schema level catches issues at the boundary)
- 1.2 Avoid Overusing Optional Fields — CRITICAL (Excessive optional fields create schemas that accept almost anything; forces null checks throughout codebase)
- 1.3 Use Coercion for Form and Query Data — CRITICAL (Form data and query params are always strings; without coercion, z.number() rejects "42" and z.boolean() rejects "true")
- 1.4 Use Enums for Fixed String Values — CRITICAL (Plain strings accept any value including typos; enums restrict to valid values and enable autocomplete)
- 1.5 Use Primitive Schemas Correctly — CRITICAL (Incorrect primitive selection causes validation to pass on wrong types; using z.any() or z.unknown() loses all type safety)
- 1.6 Use z.unknown() Instead of z.any() — CRITICAL (z.any() bypasses TypeScript's type system entirely; z.unknown() forces type narrowing before use)
- Parsing & Validation — CRITICAL
- 2.1 Avoid Double Validation — HIGH (Parsing the same data twice wastes CPU cycles; in hot paths this adds measurable latency)
- 2.2 Handle All Validation Issues Not Just First — CRITICAL (Showing only the first error forces users to fix-submit-fix repeatedly; collecting all errors improves UX dramatically)
- 2.3 Never Trust JSON.parse Output — CRITICAL (JSON.parse returns any type; unvalidated JSON allows type confusion attacks and runtime crashes)
- 2.4 Use parseAsync for Async Refinements — CRITICAL (Using parse() with async refinements throws an error; async validation silently fails or crashes the application)
- 2.5 Use safeParse() for User Input — CRITICAL (parse() throws exceptions on invalid data; unhandled exceptions crash servers and expose stack traces to users)
- 2.6 Validate at System Boundaries — CRITICAL (Validating deep in business logic allows corrupt data to propagate; validating at boundaries catches issues before they spread)
- Type Inference — HIGH
- 3.1 Distinguish z.input from z.infer for Transforms — HIGH (Using wrong type with transforms causes TypeScript errors; z.input captures pre-transform shape, z.infer captures post-transform)
- 3.2 Enable TypeScript Strict Mode — HIGH (Without strict mode, Zod's type inference is unreliable; undefined and null slip through, defeating the purpose of validation)
- 3.3 Export Both Schemas and Inferred Types — HIGH (Exporting only schemas forces consumers to derive types themselves; exporting both reduces boilerplate and improves DX)
- 3.4 Use Branded Types for Domain Safety — HIGH (Plain string IDs are interchangeable, allowing userId where orderId is expected; branded types catch these bugs at compile time)
- 3.5 Use z.infer Instead of Manual Types — HIGH (Manual type definitions drift from schemas over time; z.infer guarantees types match validation exactly)
- Error Handling — HIGH
- 4.1 Implement Internationalized Error Messages — HIGH (Hardcoded English messages exclude non-English users; error maps enable localized messages for global applications)
- 4.2 Provide Custom Error Messages — HIGH (Default messages like "Expected string, received number" confuse users; custom messages like "Email is required" are actionable)
- 4.3 Return False Instead of Throwing in Refine — HIGH (Throwing in refine stops validation early, hiding other errors; returning false allows Zod to collect all issues)
- 4.4 Use flatten() for Form Error Display — HIGH (Raw ZodError.issues requires manual path parsing; flatten() provides field-keyed errors ready for form display)
- 4.5 Use issue.path for Nested Error Location — HIGH (Without path information, users can't identify which nested field failed; path provides exact location in complex objects)
- Object Schemas — MEDIUM-HIGH
- 5.1 Choose strict() vs strip() for Unknown Keys — MEDIUM-HIGH (Default passthrough mode leaks unexpected data; strict() catches schema mismatches, strip() silently removes extras)
- 5.2 Distinguish optional() from nullable() — MEDIUM-HIGH (Confusing undefined and null semantics causes "property does not exist" vs "property is null" bugs; choose deliberately)
- 5.3 Use Discriminated Unions for Type Narrowing — MEDIUM-HIGH (Regular unions require manual type guards; discriminated unions enable TypeScript's automatic narrowing and Zod's optimized parsing)
- 5.4 Use extend() for Adding Fields — MEDIUM-HIGH (Merging objects manually loses type information; extend() preserves types and allows overriding fields safely)
- 5.5 Use partial() for Update Schemas — MEDIUM-HIGH (Creating separate update schemas duplicates definitions; partial() derives update schema from base, staying in sync)
- 5.6 Use pick() and omit() for Schema Variants — MEDIUM-HIGH (Copying fields between schemas creates duplication; pick/omit derive variants that stay in sync with base schema)
- Schema Composition — MEDIUM
- 6.1 Extract Shared Schemas into Reusable Modules — MEDIUM (Duplicating schemas across files leads to inconsistency; shared schemas ensure single source of truth)
- 6.2 Use intersection() for Type Combinations — MEDIUM (Manual field combination loses type relationships; intersection creates proper TypeScript intersection types)
- 6.3 Use pipe() for Multi-Stage Validation — MEDIUM (Chaining transforms loses intermediate type info; pipe() explicitly shows data flow through validation stages)
- 6.4 Use preprocess() for Data Normalization — MEDIUM (Validating before cleaning data causes false rejections; preprocess() normalizes input before schema validation runs)
- 6.5 Use z.lazy() for Recursive Schemas — MEDIUM (Recursive types reference themselves before definition; z.lazy() defers evaluation to enable self-referential schemas)
- Refinements & Transforms — MEDIUM
- 7.1 Add Path to Refinement Errors — MEDIUM (Errors without path show at object level; adding path highlights the specific field that failed)
- 7.2 Choose refine() vs superRefine() Correctly — MEDIUM (refine() only reports one error; superRefine() enables multiple issues and custom error codes)
- 7.3 Distinguish transform() from refine() and coerce() — MEDIUM (Using wrong method causes validation to pass with wrong data; each method has distinct purpose)
- 7.4 Use catch() for Fault-Tolerant Parsing — MEDIUM (parse() fails on first invalid field; catch() provides fallback values, enabling partial success with degraded data)
- 7.5 Use default() for Optional Fields with Defaults — MEDIUM (Manual default handling spreads logic across codebase; .default() centralizes defaults in schema)
- Performance & Bundle — LOW-MEDIUM
- 8.1 Avoid Dynamic Schema Creation in Hot Paths — LOW-MEDIUM (Zod 4's JIT compilation makes schema creation slower; creating schemas in loops adds ~0.15ms per creation)
- 8.2 Cache Schema Instances — LOW-MEDIUM (Creating schemas on every render/call wastes CPU; module-level or memoized schemas are created once)
- 8.3 Lazy Load Large Schemas — LOW-MEDIUM (Large schemas increase initial bundle and parse time; dynamic imports defer loading until needed)
- 8.4 Optimize Large Array Validation — LOW-MEDIUM (Validating 10,000 items takes ~100ms; early exits, sampling, or batching reduce time for large datasets)
- 8.5 Use Zod Mini for Bundle-Sensitive Applications — LOW-MEDIUM (Full Zod is ~17kb gzipped; Zod Mini is ~1.9kb - 85% smaller for frontend-critical bundles)
References
- https://zod.dev/
- https://zod.dev/v4
- https://github.com/colinhacks/zod
- https://zod.dev/packages/mini
- https://www.totaltypescript.com/tutorials/zod
- https://zod.dev/error-handling
- https://zod.dev/api
Source Files
This document was compiled from individual reference files. For detailed editing or extension:
| File | Description |
|---|---|
| references/_sections.md | Category definitions and impact ordering |
| assets/templates/_template.md | Template for creating new rules |
| SKILL.md | Quick reference entry point |
| metadata.json | Version and reference URLs |