# 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

1. [Schema Definition](references/_sections.md#1-schema-definition) — **CRITICAL**
   - 1.1 [Apply String Validations at Schema Definition](references/schema-string-validations.md) — 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](references/schema-avoid-optional-abuse.md) — CRITICAL (Excessive optional fields create schemas that accept almost anything; forces null checks throughout codebase)
   - 1.3 [Use Coercion for Form and Query Data](references/schema-coercion-for-form-data.md) — 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](references/schema-use-enums.md) — CRITICAL (Plain strings accept any value including typos; enums restrict to valid values and enable autocomplete)
   - 1.5 [Use Primitive Schemas Correctly](references/schema-use-primitives-correctly.md) — 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()](references/schema-use-unknown-not-any.md) — CRITICAL (z.any() bypasses TypeScript's type system entirely; z.unknown() forces type narrowing before use)
2. [Parsing & Validation](references/_sections.md#2-parsing-&-validation) — **CRITICAL**
   - 2.1 [Avoid Double Validation](references/parse-avoid-double-validation.md) — 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](references/parse-handle-all-issues.md) — 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](references/parse-never-trust-json.md) — CRITICAL (JSON.parse returns any type; unvalidated JSON allows type confusion attacks and runtime crashes)
   - 2.4 [Use parseAsync for Async Refinements](references/parse-async-for-async-refinements.md) — CRITICAL (Using parse() with async refinements throws an error; async validation silently fails or crashes the application)
   - 2.5 [Use safeParse() for User Input](references/parse-use-safeparse.md) — CRITICAL (parse() throws exceptions on invalid data; unhandled exceptions crash servers and expose stack traces to users)
   - 2.6 [Validate at System Boundaries](references/parse-validate-early.md) — CRITICAL (Validating deep in business logic allows corrupt data to propagate; validating at boundaries catches issues before they spread)
3. [Type Inference](references/_sections.md#3-type-inference) — **HIGH**
   - 3.1 [Distinguish z.input from z.infer for Transforms](references/type-input-vs-output.md) — 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](references/type-enable-strict-mode.md) — 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](references/type-export-schemas-and-types.md) — 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](references/type-branded-types.md) — 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](references/type-use-z-infer.md) — HIGH (Manual type definitions drift from schemas over time; z.infer guarantees types match validation exactly)
4. [Error Handling](references/_sections.md#4-error-handling) — **HIGH**
   - 4.1 [Implement Internationalized Error Messages](references/error-i18n.md) — HIGH (Hardcoded English messages exclude non-English users; error maps enable localized messages for global applications)
   - 4.2 [Provide Custom Error Messages](references/error-custom-messages.md) — 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](references/error-avoid-throwing-in-refine.md) — 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](references/error-use-flatten.md) — 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](references/error-path-for-nested.md) — HIGH (Without path information, users can't identify which nested field failed; path provides exact location in complex objects)
5. [Object Schemas](references/_sections.md#5-object-schemas) — **MEDIUM-HIGH**
   - 5.1 [Choose strict() vs strip() for Unknown Keys](references/object-strict-vs-strip.md) — MEDIUM-HIGH (Default passthrough mode leaks unexpected data; strict() catches schema mismatches, strip() silently removes extras)
   - 5.2 [Distinguish optional() from nullable()](references/object-optional-vs-nullable.md) — 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](references/object-discriminated-unions.md) — 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](references/object-extend-for-composition.md) — MEDIUM-HIGH (Merging objects manually loses type information; extend() preserves types and allows overriding fields safely)
   - 5.5 [Use partial() for Update Schemas](references/object-partial-for-updates.md) — 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](references/object-pick-omit.md) — MEDIUM-HIGH (Copying fields between schemas creates duplication; pick/omit derive variants that stay in sync with base schema)
6. [Schema Composition](references/_sections.md#6-schema-composition) — **MEDIUM**
   - 6.1 [Extract Shared Schemas into Reusable Modules](references/compose-shared-schemas.md) — MEDIUM (Duplicating schemas across files leads to inconsistency; shared schemas ensure single source of truth)
   - 6.2 [Use intersection() for Type Combinations](references/compose-intersection.md) — MEDIUM (Manual field combination loses type relationships; intersection creates proper TypeScript intersection types)
   - 6.3 [Use pipe() for Multi-Stage Validation](references/compose-pipe.md) — MEDIUM (Chaining transforms loses intermediate type info; pipe() explicitly shows data flow through validation stages)
   - 6.4 [Use preprocess() for Data Normalization](references/compose-preprocess.md) — MEDIUM (Validating before cleaning data causes false rejections; preprocess() normalizes input before schema validation runs)
   - 6.5 [Use z.lazy() for Recursive Schemas](references/compose-lazy-recursive.md) — MEDIUM (Recursive types reference themselves before definition; z.lazy() defers evaluation to enable self-referential schemas)
7. [Refinements & Transforms](references/_sections.md#7-refinements-&-transforms) — **MEDIUM**
   - 7.1 [Add Path to Refinement Errors](references/refine-add-path.md) — MEDIUM (Errors without path show at object level; adding path highlights the specific field that failed)
   - 7.2 [Choose refine() vs superRefine() Correctly](references/refine-vs-superrefine.md) — MEDIUM (refine() only reports one error; superRefine() enables multiple issues and custom error codes)
   - 7.3 [Distinguish transform() from refine() and coerce()](references/refine-transform-coerce.md) — MEDIUM (Using wrong method causes validation to pass with wrong data; each method has distinct purpose)
   - 7.4 [Use catch() for Fault-Tolerant Parsing](references/refine-catch.md) — 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](references/refine-defaults.md) — MEDIUM (Manual default handling spreads logic across codebase; .default() centralizes defaults in schema)
8. [Performance & Bundle](references/_sections.md#8-performance-&-bundle) — **LOW-MEDIUM**
   - 8.1 [Avoid Dynamic Schema Creation in Hot Paths](references/perf-avoid-dynamic-creation.md) — 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](references/perf-cache-schemas.md) — LOW-MEDIUM (Creating schemas on every render/call wastes CPU; module-level or memoized schemas are created once)
   - 8.3 [Lazy Load Large Schemas](references/perf-lazy-loading.md) — LOW-MEDIUM (Large schemas increase initial bundle and parse time; dynamic imports defer loading until needed)
   - 8.4 [Optimize Large Array Validation](references/perf-arrays.md) — 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](references/perf-zod-mini.md) — LOW-MEDIUM (Full Zod is ~17kb gzipped; Zod Mini is ~1.9kb - 85% smaller for frontend-critical bundles)

---

## References

1. [https://zod.dev/](https://zod.dev/)
2. [https://zod.dev/v4](https://zod.dev/v4)
3. [https://github.com/colinhacks/zod](https://github.com/colinhacks/zod)
4. [https://zod.dev/packages/mini](https://zod.dev/packages/mini)
5. [https://www.totaltypescript.com/tutorials/zod](https://www.totaltypescript.com/tutorials/zod)
6. [https://zod.dev/error-handling](https://zod.dev/error-handling)
7. [https://zod.dev/api](https://zod.dev/api)

---

## Source Files

This document was compiled from individual reference files. For detailed editing or extension:

| File                                                            | Description                              |
| --------------------------------------------------------------- | ---------------------------------------- |
| [references/\_sections.md](references/_sections.md)             | Category definitions and impact ordering |
| [assets/templates/\_template.md](assets/templates/_template.md) | Template for creating new rules          |
| [SKILL.md](SKILL.md)                                            | Quick reference entry point              |
| [metadata.json](metadata.json)                                  | Version and reference URLs               |
