Capítulo 48 de 61
Libraries built on Zod should depend on it as a peer dependency, import only from the stable "zod/v4/core" subpath (not "zod", "zod/v4", or "zod/v4/mini"), and — if genuinely accepting arbitrary user-defined schemas rather than needing Zod-specific behavior — consider Standard Schema instead of a hard Zod dependency at all.
"zod": "^4.0.0" under peerDependencies (and duplicate it under devDependencies for local development) so consumers "bring their own Zod" version."zod/v4/core": this is the permanent, version-stable subpath shared by both Zod Classic and Zod Mini — it defines the $-prefixed base classes both implementations extend. Avoid "zod" (its meaning shifts between major versions), and avoid "zod/v4"/"zod/v4/mini" directly, since code built against either one won't work with the other."^3.25.0 || ^4.0.0" (the "zod/v4" subpath exists starting at 3.25.0) and import "zod/v3" alongside "zod/v4/core"; distinguish schema versions at runtime by checking for the "_zod" property (present only on Zod 4 schemas). New libraries (or new major versions) should target Zod 4 only — Zod 3 is functionally end-of-life, security/bug fixes only, no new features."zod/v4/core" types/functions; since both Classic and Mini extend the same core classes, a function written against the core interface accepts schemas from either package transparently.// package.json
{
"peerDependencies": { "zod": "^4.0.0" },
"devDependencies": { "zod": "^4.0.0" }
}
// correct: import the stable core subpath
import * as z4 from "zod/v4/core";
export function acceptObjectSchema<T extends z4.$ZodObject>(schema: T) {
z4.parse(schema, { /* data */ });
schema._zod.def.shape;
}
// works transparently with both packages
import * as z from "zod";
acceptObjectSchema(z.object({ name: z.string() }));
import * as zm from "zod/mini";
acceptObjectSchema(zm.object({ name: zm.string() }));
// distinguishing Zod 3 vs Zod 4 schemas at runtime
if ("_zod" in schema) {
schema._zod.def; // Zod 4
} else {
schema._def; // Zod 3
}
"zod/v4" or "zod/v4/mini" directly in library code: locks the library to one flavor and breaks for users of the other.function f<T>(schema: z4.$ZodType<T>): this loses the specific subclass information — TypeScript can't infer which schema type was actually passed, so callers lose access to type-specific methods on the result."zod/v4/core" is the one import path guaranteed to keep working across future major versions and both Classic/Mini flavors — treat it as the only sanctioned import for library internals."zod/v4/core" package this chapter tells you to depend on.