Capítulo 59 de 61

Chapter 59: Migration Guide — Internal & Architectural Changes

Core Idea

Most Zod 4 internal restructuring (generics, the new zod/v4/core package, the _zod.def internals location, and the refinement/transform class split) doesn't affect typical application code, but matters directly to anyone building tooling on top of Zod.

Reference Tables

AreaZod 3Zod 4
ZodType genericsZodType<Output, Def extends ZodTypeDef, Input = Output>ZodType<Output = unknown, Input = unknown> — the Def generic is gone, Input now defaults to unknown instead of Output
z.ZodTypeAnyneeded as a catch-all typeunnecessary — plain z.ZodType now serves that purpose
Shared core codenot split outmoved to zod/v4/core, re-exported from both zod and zod/mini as the z.core namespace
Internal definition property._def._zod.def
Refinements & transformsboth lived inside a ZodEffects wrapper classrefinements now live as "checks" directly inside each schema; transforms live in a dedicated ZodTransform class
.transform() return typeits own effects wrapperreturns a ZodPipe<OriginalSchema, ZodTransform>
z.preprocess() return typeZodPreprocess instancereturns a ZodPipe<ZodTransform, TargetSchema>
Branded typesdedicated ZodBranded wrapper classdirect modification of the inferred type, no wrapper class; user-facing API unchanged

Code Examples

// generics: T is inferred as the caller's actual schema class, not a fixed Output type
function inferSchema<T extends z.ZodType>(schema: T): T { return schema; }
inferSchema(z.string()); // => ZodString

// zod/v4/core re-exported as z.core from the main package
import * as z from "zod";
function handleError(iss: z.core.$ZodError) { /* ... */ }

// standalone transforms are now first-class
const schema = z.transform(input => String(input));
schema.parse(12); // => "12"

// .transform() now composes via ZodPipe under the hood
z.string().transform(val => val); // ZodPipe<ZodString, ZodTransform>
  • What it demonstrates: the simplified generic signature, accessing core types via z.core, and the new first-class standalone-transform capability.

Key Takeaways

  1. Application code almost never touches these internals directly — this chapter matters mainly if you're building a schema-introspection tool, code generator, or Zod-extending library.
  2. ._def moved to ._zod.def — any tooling reading Zod internals directly needs updating for this new location.
  3. The ZodEffects/ZodBranded/ZodPreprocess classes are gone; tooling that pattern-matched on those specific class names needs to switch to checking ._zod.def.type/.def.check discriminants instead.

Connects To

  • Zod Core — Schema Classes & Internals: the current structure of _zod.def and the core class hierarchy this migration moved toward.
  • For Library Authors — Peer Dependencies & Subpaths: the "zod/v4/core" import path this restructuring introduced.