zod-v4

star 5

Zod v4 validation library reference. Auto-loads when working with Zod schemas, validation, z.object, z.string, z.infer, safeParse, transforms, discriminatedUnion.

nklisch By nklisch schedule Updated 3/4/2026

name: zod-v4 description: > Zod v4 validation library reference. Auto-loads when working with Zod schemas, validation, z.object, z.string, z.infer, safeParse, transforms, discriminatedUnion.

Zod v4 Reference

Version: 4.x Docs: https://zod.dev

See reference.md for the full API (imports, types, parsing, schema manipulation, error handling, common patterns).

Zod 4 Breaking Changes from 3.x

  1. Records with enum keys are exhaustive - All keys required by default

    // v4: produces { a: number; b: number } (both required)
    z.record(z.enum(['a', 'b']), z.number())
    
    // For optional keys, use z.partialRecord()
    z.partialRecord(z.enum(['a', 'b']), z.number()) // { a?: number; b?: number }
    
  2. Error customization unified - message, invalid_type_error, required_error removed

    // v3
    z.string({ required_error: 'Required', invalid_type_error: 'Must be string' })
    
    // v4
    z.string({ error: (iss) => iss.input === undefined ? 'Required' : 'Must be string' })
    
  3. Default behavior - .default() must match output type (use .prefault() for pre-parse defaults)

  4. ZodError.errors removed - Use ZodError.issues instead

Key Gotchas

Optional vs Nullable vs Nullish

Method Type Use When
.optional() T | undefined Field can be absent
.nullable() T | null Field uses null as empty
.nullish() T | null | undefined Messy external data

Don't chain .optional().nullable() — use .nullish()

z.interface() for Precise Optionality (v4)

z.interface({ "name?": z.string() })           // { name?: string } — key may be omitted
z.interface({ name: z.string().optional() })   // { name: string | undefined } — key required

Performance

  • Zod 4 is 14x faster for strings, 7x for arrays, 6.5x for objects vs v3
  • Use z.discriminatedUnion() over z.union() for object schemas
  • Cache parsed results — don't parse the same data repeatedly

Anti-Patterns

  1. Don't use .any() instead of .unknown().unknown() forces type narrowing
  2. Don't parse the same data repeatedly — Parse once at boundaries
  3. Don't ignore .safeParse() errors — Always check result.success
  4. Don't use refinements for transformations — Use .transform() for conversion, .refine() for validation
  5. Don't throw in refinement functions — Return false, Zod handles errors
  6. Don't nest .safeParse() calls — Compose schemas instead
  7. Don't use regular unions for discriminated data — Use z.discriminatedUnion()
  8. Don't mix sync and async schemas — If any part is async, use async parsing
  9. Don't cast after validation — Derive types with z.infer<typeof schema>
  10. Don't maintain separate types and schemas — Schema-first, derive types
  11. Don't chain .optional().nullable() — Use .nullish()
Install via CLI
npx skills add https://github.com/nklisch/skills --skill zod-v4
Repository Details
star Stars 5
call_split Forks 3
navigation Branch main
article Path SKILL.md
More from Creator