5. zod/mini, zod/v4/core & zod/compile Reference
Zod v4 is architected as a layered library ecosystem: zod/v4/core provides the zero-method trait engine ($constructor, $ZodType, $ZodCheck, ParsePayload, JSONSchemaGenerator), zod/mini layers a tree-shakable functional wrapper (ZodMiniType) with standalone check and combinator functions for strict bundle-size budgets, and zod/compile provides Ahead-of-Time (AOT) and first-parse JIT code generation (compile, compileFn, withParser).
Source Code
from drawlib import canvas
from drawlib.diagrams.architecture import ArchitectureDiagram, Node, NodeGroup, PhosphorIcon
from drawlib.styles import Styles
canvas.clear()
canvas.setup(width=188, height=96, dpi=150)
d = ArchitectureDiagram(
node_style=Styles.Primary,
node_text_style=Styles.DarkBold.patch(text_size=10.0),
edge_style=Styles.DarkBold,
edge_text_style=Styles.Dark.patch(text_size=10.0),
node_card_style=Styles.Neutral,
title="Layered Architecture: zod/mini, zod/v4/core & zod/compile",
)
# Left Group: zod/mini (Tree-Shakable Functional API) (node width=46 -> center x = 5 + 23 = 28)
mini_grp = d.add(
NodeGroup(title="1. zod/mini (Tree-Shakable)", padding=5.0),
xy=(0.0, 0.0),
)
mini_type = mini_grp.add(
Node("ZodMiniType<O, I>\n.parse / .safeParse\n.check / .register / .brand", width=46, height=20, icon=PhosphorIcon.FEATHER, icon_size=6.5, card_style=Styles.PrimaryNeutral),
xy=(28.0, 52.0),
)
mini_fns = mini_grp.add(
Node("Standalone Functions\nz.minLength / z.gt / z.regex\nz.optional / z._default / z.pipe", width=46, height=20, icon=PhosphorIcon.FUNCTION, icon_size=6.5, card_style=Styles.Neutral),
xy=(28.0, 15.0),
)
# Center Group: zod/v4/core (Shared Trait Engine) (node width=42 -> center x = 5 + 21 = 26)
core_grp = d.add(
NodeGroup(title="2. zod/v4/core (Shared Engine)", padding=5.0),
xy=(66.0, 0.0),
)
core_ctor = core_grp.add(
Node("core.$constructor(name, init)\n$ZodType & _zod.run()\nParsePayload / traits Set", width=42, height=20, icon=PhosphorIcon.CPU, icon_size=6.5, style=Styles.WhiteBold, card_style=Styles.PrimaryFlat, text_style=Styles.WhiteBold.patch(text_size=10.0)),
xy=(26.0, 52.0),
)
core_chk = core_grp.add(
Node("$ZodCheck & JSONSchema\n_zod.check(payload)\nJSONSchemaGenerator", width=42, height=20, icon=PhosphorIcon.SHIELD_CHECK, icon_size=6.5, card_style=Styles.Neutral),
xy=(26.0, 15.0),
)
# Right Group: zod/compile (AOT & Fast-Path Compiler) (node width=46 -> center x = 5 + 23 = 28)
comp_grp = d.add(
NodeGroup(title="3. zod/compile (AOT Fast Path)", padding=5.0),
xy=(128.0, 0.0),
)
comp_api = comp_grp.add(
Node("Compiler Entry Points\nz.compile(schema, opts)\ncompileFn / withParser", width=46, height=20, icon=PhosphorIcon.LIGHTNING, icon_size=6.5, style=Styles.WhiteBold, card_style=Styles.AccentFlat, text_style=Styles.WhiteBold.patch(text_size=10.0)),
xy=(28.0, 52.0),
)
comp_shim = comp_grp.add(
Node("Global Post-Processor\nimport 'zod/compile'\nINVALID fallback to _zod.run", width=46, height=20, icon=PhosphorIcon.GEAR_SIX, icon_size=6.5, card_style=Styles.PrimaryNeutral),
xy=(28.0, 15.0),
)
# Connections
d.connect(mini_type, core_ctor, padding=1.5)
d.connect(mini_fns, core_chk, padding=1.5)
d.connect(core_chk, core_ctor, label="def.checks", padding=1.5)
core_ctor.fork([comp_api, comp_shim], at_x=122.0, padding=1.5)
d.draw(xy=(94.0, 46.0), align="center")
canvas.save()
classZodMiniType (zod/mini)#
Imported from zod/mini (or zod/v4-mini), ZodMiniType<Output, Input, Internals> strips away the dozens of convenience wrapper/check methods on ZodType (such as .optional(), .nullable(), .default(), .min(), .max(), .email()) so bundlers (Rollup, esbuild, Webpack, Vite) can tree-shake every unused schema and check out of client bundles.
ZodMiniType Instance Surface#
| Member | Kind | Signature / Type | Description |
|---|---|---|---|
schema.type |
Property | Internals["def"]["type"] |
Literal string discriminator ("string", "number", "object", "pipe", etc.). |
schema.def |
Property | Internals["def"] |
Underlying $ZodTypeDef configuration object. |
schema._zod |
Property | Internals ($ZodTypeInternals<O, I>) |
Core internal runtime slot (_zod.run, _zod.parse, _zod.traits, _zod.bag). |
schema["~standard"] |
Getter | $ZodStandardSchema<this> |
Standard Schema v1 (StandardSchemaV1.Props<I, O>) interoperability descriptor. |
schema.parse(data, params?) |
Method | (data: unknown, params?: ParseContext) => O |
Synchronously parses data or throws ZodError. |
schema.safeParse(data, params?) |
Method | (data: unknown, params?: ParseContext) => SafeParseResult<O> |
Synchronously parses data and returns { success, data | error }. |
schema.parseAsync(data, params?) |
Method | (data: unknown, params?: ParseContext) => Promise<O> |
Asynchronous parse. |
schema.safeParseAsync(data, params?) |
Method | (data: unknown, params?: ParseContext) => Promise<SafeParseResult<O>> |
Asynchronous safe parse. |
schema.check(...checks) / schema.with(...checks) |
Method | (...checks: (CheckFn<O> | $ZodCheck<O>)[]) => this |
Clones the schema and attaches one or more standalone $ZodCheck descriptors. |
schema.register(registry, meta?) |
Method | <R extends $ZodRegistry>(registry: R, meta?: ...) => this |
Registers metadata for this in registry and returns this. |
schema.brand<B, Dir>() |
Method | <T extends PropertyKey, Dir extends "in" | "out" | "inout" = "out">(val?: T) => $ZodBranded<this, T, Dir> |
Adds a nominal static brand ($brand<T>) to the output, input, or both types. |
schema.clone(def?, params?) |
Method | (def?: Internals["def"], params?: { parent: boolean }) => this |
Clones the schema instance with an optional updated definition. |
schema.apply(fn, ...args) |
Method | <T, A extends unknown[]>(fn: (s: this, ...args: A) => T, ...args: A) => T |
Pipes this into a helper function fn(this, ...args) for fluent composition. |
import * as z from "zod/mini";
const UserMiniSchema = z.object({
id: z.uuid(),
username: z.string().check(z.trim(), z.minLength(3), z.maxLength(24)),
age: z.optional(z.int().check(z.gte(18))),
});
const parsed = UserMiniSchema.parse({
id: "550e8400-e29b-41d4-a716-446655440000",
username: " alice ",
});
functionzod/mini Standalone Checks (z.minLength, z.maxLength, z.gt, z.lt, ...)#
Because ZodMiniString, ZodMiniNumber, ZodMiniArray, and ZodMiniSet do not carry prototype check methods (like .min() or .regex()), all constraints and in-place mutations in zod/mini are composed via schema.check(...) using standalone check factories.
zod/mini Check & Refinement Functions#
| Category | Exported Functions in zod/mini |
Target Schemas |
|---|---|---|
| Numeric & Date Bounds | z.lt(v), z.lte(v) (z.maximum), z.gt(v), z.gte(v) (z.minimum), z.positive(), z.negative(), z.nonpositive(), z.nonnegative(), z.multipleOf(v) |
z.number(), z.int(), z.bigint(), z.date() |
| Length Constraints | z.minLength(n), z.maxLength(n), z.length(n) |
z.string(), z.array(), z.file() |
| Collection / File Size | z.minSize(n), z.maxSize(n), z.size(n) |
z.map(), z.set(), z.file() |
| String Pattern & Case | z.regex(re), z.lowercase(), z.uppercase(), z.includes(s), z.startsWith(s), z.endsWith(s) |
z.string() and string format schemas |
| String Canonicalization | z.trim(), z.toLowerCase(), z.toUpperCase(), z.normalize(form?), z.slugify() |
z.string() |
| Object / File / Custom | z.property(k, schema), z.properties(shape), z.mime(types), z.overwrite(fn), z.check(fn), z.refine(fn, params?), z.superRefine(fn, params?) |
Any compatible ZodMiniType |
functionzod/mini Wrapper Functions (z.optional, z.nullable, z._default, z.prefault)#
In zod/mini, schema wrappers and combinators are invoked as top-level functions wrapping an inner schema rather than chained methods.
zod/mini Wrapper & Combinator Functions#
zod/mini Function |
Classic zod Method Equivalent |
Return Type | Description |
|---|---|---|---|
z.optional(schema) |
schema.optional() |
ZodMiniOptional<T> |
Accepts undefined and passes it through (output<T> | undefined). |
z.exactOptional(schema) |
schema.exactOptional() |
ZodMiniExactOptional<T> |
Allows omitting the key on an object without allowing explicit undefined values. |
z.nullable(schema) |
schema.nullable() |
ZodMiniNullable<T> |
Accepts null and passes it through (output<T> | null). |
z.nullish(schema) |
schema.nullish() |
ZodMiniOptional<ZodMiniNullable<T>> |
Accepts both null and undefined (z.optional(z.nullable(schema))). |
z.nonoptional(schema, params?) |
schema.nonoptional(params?) |
ZodMiniNonOptional<T> |
Rejects undefined inputs and removes undefined from the inferred output type. |
z._default(schema, valueOrFn) |
schema.default(valueOrFn) |
ZodMiniDefault<T> |
Short-circuits undefined inputs and returns the default output<T> value without running schema. |
z.prefault(schema, valueOrFn) |
schema.prefault(valueOrFn) |
ZodMiniPrefault<T> |
Substitutes undefined inputs with a default input<T> value and parses it through schema. |
z.catch(schema, valueOrFn) |
schema.catch(valueOrFn) |
ZodMiniCatch<T> |
Returns a fallback value whenever schema fails validation. |
z.readonly(schema) |
schema.readonly() |
ZodMiniReadonly<T> |
Calls Object.freeze() on parsed outputs and marks the static type Readonly<O>. |
z.pipe(inSchema, outSchema) |
inSchema.pipe(outSchema) |
ZodMiniPipe<A, B> |
Chains inSchema into outSchema. |
z.codec(inSchema, outSchema, { decode, encode }) |
z.codec(...) |
ZodMiniCodec<A, B> |
Constructs a bidirectional codec in zod/mini. |
import * as z from "zod/mini";
// Composing wrappers functionally in zod/mini
const EnvPortSchema = z._default(
z.pipe(z.string().check(z.trim()), z.coerce.number().check(z.gte(1024), z.lte(65535))),
8080,
);
EnvPortSchema.parse(undefined); // => 8080
EnvPortSchema.parse(" 3000 "); // => 3000
function$constructor (zod/v4/core)#
At the heart of zod/v4/core is $constructor(name, initializer, proto?, params?), a lightweight trait-based class factory that enables multiple inheritance across zod/v4/core, zod (Classic), and zod/mini while keeping instanceof checks O(1) via Symbol.hasInstance and inst._zod.traits.
$constructor Signature & Lifecycle#
export interface $constructor<T extends ZodTrait, D = T["_zod"]["def"]> {
new (def: D): T;
init(inst: T, def: D): asserts inst is T;
}
export function $constructor<T extends ZodTrait, D = T["_zod"]["def"]>(
name: string,
initializer: (inst: T, def: D) => void,
proto?: ProtoOf<T>,
params?: { Parent?: typeof Class }
): $constructor<T, D>;
| Mechanism | Runtime Behavior |
|---|---|
new Ctor(def) |
Allocates inst, invokes Ctor.init(inst, def), flushes any inst._zod.deferred initializers, and invokes globalConfig.postProcessor?.(inst) (used by zod/compile). |
Ctor.init(inst, def) |
Attaches non-enumerable inst._zod ({ def, constr, traits: Set }) on first call, guards against duplicate initialization via inst._zod.traits.has(name), adds name to traits, runs initializer(inst, def), and installs proto descriptors once per prototype chain. |
inst instanceof Ctor |
Custom [Symbol.hasInstance] checks inst?._zod?.traits?.has(name), allowing a ZodString or ZodMiniString instance to satisfy inst instanceof core.$ZodString AND inst instanceof core.$ZodType. |
interface$ZodType & $ZodTypeInternals (zod/v4/core)#
Every schema in Zod v4 implements $ZodType<O, I, Internals>, which carries only two properties: _zod ($ZodTypeInternals<O, I>) and "~standard" (StandardSchemaV1.Props<I, O>).
$ZodTypeInternals<O, I> & ParsePayload<T> Reference#
| Property / Method | Type | Description |
|---|---|---|
_zod.def |
$ZodTypeDef |
Declarative schema definition ({ type, error?, checks? }). |
_zod.version |
{ major: 4, minor: 6, patch: ... } |
@zod/core semantic version descriptor. |
_zod.traits |
Set<string> |
Set of $constructor trait names composed into this instance (e.g., {"$ZodType", "$ZodString", "ZodType", "ZodString"}). |
_zod.run(payload, ctx) |
(payload: ParsePayload, ctx: ParseContextInternal) => MaybeAsync<ParsePayload> |
Full execution entry point: parses input AND executes all attached def.checks. |
_zod.parse(payload, ctx) |
(payload: ParsePayload, ctx: ParseContextInternal) => MaybeAsync<ParsePayload> |
Base type-validation routine before def.checks are executed. |
_zod.bag |
Record<string, unknown> |
Aggregated metadata bag populated by checks (onattach) and zod/compile (validator, fallbackRun). |
_zod.optin / _zod.optout |
"optional" | "defaulted" | undefined |
Tracks whether object properties using this schema are optional on input or output. |
_zod.values / _zod.pattern |
PrimitiveSet | undefined / RegExp | undefined |
Exhaustive literal set (for z.record keys / discriminated unions) and regex representation (for z.templateLiteral). |
payload.value |
T |
Current mutable value inside ParsePayload<T> as it flows through _zod.parse and _zod.def.checks. |
payload.issues |
$ZodRawIssue[] |
Mutable array of raw issues accumulated during validation. |
class$ZodCheck (zod/v4/core)#
$ZodCheck<T> is the base $constructor for all post-parse constraints and in-place mutations in packages/zod/src/v4/core/checks.ts.
$ZodCheckInternals<T> Structure#
| Member | Type | Description |
|---|---|---|
_zod.def |
$ZodCheckDef |
{ check: string, error?: $ZodErrorMap, abort?: boolean, when?: (payload: ParsePayload) => boolean }. |
_zod.check(payload) |
(payload: ParsePayload<T>) => MaybeAsync<void> |
Evaluates the constraint against payload.value (pushing to payload.issues on failure) or mutates payload.value in place. |
_zod.onattach |
((schema: $ZodType) => void)[] |
Callbacks invoked when the check is attached to a schema, used to record constraints (minimum, maximum, format, pattern) into schema._zod.bag. |
import * as core from "zod/v4/core";
// Defining a custom reusable $ZodCheck in zod/v4/core
export const $ZodCheckEven = core.$constructor<{ _zod: core.$ZodCheckInternals<number> }>(
"$ZodCheckEven",
(inst, def) => {
core.$ZodCheck.init(inst, def);
inst._zod.onattach.push((schema) => {
schema._zod.bag.even = true;
});
inst._zod.check = (payload) => {
if (payload.value % 2 !== 0) {
payload.issues.push({
code: "custom",
input: payload.value,
inst,
message: "Expected an even number",
});
}
};
},
);
classJSONSchemaGenerator (zod/v4/core)#
Exported from zod/v4/core, JSONSchemaGenerator provides the stateful two-phase (process -> emit) class interface underlying z.toJSONSchema(). While new application code should prefer the functional z.toJSONSchema(schema, params) API, JSONSchemaGenerator remains available in zod/v4/core for custom multi-schema pipelines.
JSONSchemaGenerator Methods#
| Method | Signature | Description |
|---|---|---|
new JSONSchemaGenerator(params?) |
constructor(params?: Pick<JSONSchemaGeneratorParams, "metadata" | "target" | "unrepresentable" | "override" | "io">) |
Initializes a ToJSONSchemaContext with allProcessors and target specification ("draft-2020-12" default). |
gen.process(schema, params?) |
(schema: $ZodType, params?: ProcessParams) => JSONSchema.BaseSchema |
Traverses schema, populates this.ctx.seen, and registers cycle/reuse references. Must be called before emit(). |
gen.emit(schema, params?) |
(schema: $ZodType, params?: EmitParams) => JSONSchema.BaseSchema |
Extracts shared $defs via extractDefs(), resolves $ref pointers via finalize(), and returns the plain JSON Schema object. |
functioncompile / compileFn / withParser (zod/compile)#
Zod v4 includes a dedicated schema compiler (packages/zod/src/v4/core/compile.ts and side-effect entry point zod/compile) that generates specialized JavaScript validation functions for synchronous forward parsing. On valid inputs, the compiled fast path builds the output directly without allocating ParsePayload or ParseContext; on invalid inputs, it returns the sentinel symbol z.INVALID (Symbol.for("zod.compile.invalid")) and falls back to the standard _zod.run interpreter so error maps, paths, and issue payloads remain 100% identical.
Compiler API Reference#
| Export / Entry Point | Signature | Description |
|---|---|---|
import "zod/compile" |
Side-effect module import | Installs globalConfig.postProcessor so every schema constructed after the import is lazily AOT-compiled on its first synchronous forward parse. Respects z.config({ jitless: true }). |
z.compile(schema, options?) |
<T extends SomeType>(schema: T, options?: { strict?: boolean }) => T |
Eagerly compiles schema and returns a clone with a compiled _zod.run and _zod.bag.validator. By default returns schema unchanged if unsupported; throws ZodCompileUnsupportedError or ZodCompileAsyncError when { strict: true }. |
compileFn(schema, options?) |
<T extends SomeType>(schema: T, options?: { debug?: boolean; assertOnly?: boolean }) => CompiledFn<output<T>> |
(zod/v4/core) Low-level codegen returning ((input: unknown) => output<T> | INVALID) & { code?: string; definite?: boolean }. When assertOnly: true, omits output object allocation for z.validate(). |
z.withParser(schema, parser) |
<T extends SomeType>(schema: T, parser: (input: unknown) => output<T> | INVALID) => T |
Attaches a pre-generated AOT parser function (e.g., emitted at build time for strict CSP / jitless environments) to a clone of schema. |
z.INVALID |
unique symbol (Symbol.for("zod.compile.invalid")) |
Sentinel returned by compiled parsers when input fails validation, triggering the runtime _zod.run fallback. |
// Mode A: Automatic global compilation (place at application entry point)
import "zod/compile";
import * as z from "zod";
// Mode B: Explicit per-schema compilation with strict error checking
const OrderSchema = z.compile(
z.object({
orderId: z.uuid(),
items: z.array(z.object({ sku: z.string(), qty: z.int().positive() })),
}),
{ strict: true },
);
const order = OrderSchema.parse(rawOrder);
interfaceStandardSchemaV1 (~standard)#
Every Zod v4 schema (ZodType, ZodMiniType, and $ZodType) implements the cross-library Standard Schema v1 (StandardSchemaV1) and Standard JSON Schema v1 (StandardJSONSchemaV1) specifications under the schema["~standard"] property, allowing tRPC, TanStack Form/Router, Hono, Next.js Server Actions, and OpenAPI generators to accept Zod v4 schemas without vendor-specific adapters.
Source Code
from drawlib import canvas
from drawlib.diagrams.class_diagram import ClassDiagram, ClassNode
from drawlib.fonts import FontRoboto, FontSourceCode
from drawlib.styles import Styles
canvas.clear()
canvas.setup(width=188, height=96, dpi=150)
cd = ClassDiagram(
node_style=Styles.Neutral.patch(text_font=FontSourceCode.ROBOTO_MONO, text_size=9.5),
header_style=Styles.PrimaryNeutral.patch(text_font=FontRoboto.ROBOTO_BOLD, text_size=10.5),
edge_style=Styles.DarkBold,
edge_text_style=Styles.Dark.patch(text_size=9.5),
title="StandardSchemaV1 & StandardJSONSchemaV1 (~standard Contract)",
)
# Left: Zod Schema
zod_schema = cd.add(
ClassNode("ZodType<O, I> / ZodMiniType<O, I>", width=50, header_style=Styles.SecondaryNeutral.patch(text_font=FontRoboto.ROBOTO_BOLD, text_size=10.5))
.add_attribute("~standard", "StandardSchemaProps<I, O>", visibility="+")
.add_method("parse", "data: unknown", "O")
.add_method("toJSONSchema", "params?", "BaseSchema"),
xy=(28.0, 48.0),
)
# Center: ~standard Props
std_props = cd.add(
ClassNode("StandardSchemaProps<I, O>", width=54, header_style=Styles.PrimaryNeutral)
.add_attribute("version", "1", visibility="+")
.add_attribute("vendor", "'zod'", visibility="+")
.add_attribute("types", "{ input: I, output: O }", visibility="+")
.add_attribute("jsonSchema", "StandardJSONSchemaV1.Converter", visibility="+")
.add_method("validate", "val: unknown", "Result<O> | Promise"),
xy=(94.0, 48.0),
)
# Right Top: Validation Result
std_res = cd.add(
ClassNode("StandardSchemaV1.Result<O>", width=52, header_style=Styles.PrimaryNeutral)
.add_attribute("SuccessResult<O>", "{ value: O }")
.add_attribute("FailureResult", "{ issues: Issue[] }"),
xy=(160.0, 68.0),
)
# Right Bottom: JSON Schema Converter
std_json = cd.add(
ClassNode("StandardJSONSchemaV1.Converter", width=52, header_style=Styles.PrimaryNeutral)
.add_method("input", "opts: Options", "JSONSchema")
.add_method("output", "opts: Options", "JSONSchema"),
xy=(160.0, 26.0),
)
cd.connect(zod_schema, std_props, "composition", directed=True, start_side="right", end_side="left")
cd.connect(std_props, std_res, "dependency", start_side="right", end_side="left")
cd.connect(std_props, std_json, "composition", directed=True, start_side="right", end_side="left")
cd.draw(xy=(94.0, 46.0), align="center")
canvas.save()
schema["~standard"] Contract Reference#
| Property / Method | Type | Description |
|---|---|---|
schema["~standard"].version |
1 |
Fixed Standard Schema specification version number (1). |
schema["~standard"].vendor |
"zod" |
Vendor identifier string ("zod"). |
schema["~standard"].validate(value, opts?) |
(value: unknown, options?: StandardSchemaV1.Options) => Result<O> | Promise<Result<O>> |
Executes validation and returns { value: O } on success or { issues: $ZodIssue[] } on failure (synchronously when possible, or a Promise if async checks are present). |
schema["~standard"].jsonSchema.input(opts) |
(options: { target: Target; libraryOptions?: Record<string, unknown> }) => Record<string, unknown> |
Generates a JSON Schema ("draft-2020-12", "draft-07", "openapi-3.0") for the schema's input type (io: "input"). Installed on Classic ZodType. |
schema["~standard"].jsonSchema.output(opts) |
(options: { target: Target; libraryOptions?: Record<string, unknown> }) => Record<string, unknown> |
Generates a JSON Schema for the schema's output type (io: "output"). Installed on Classic ZodType. |
StandardSchemaV1.InferInput<S> / InferOutput<S> |
Type Helpers | Vendor-agnostic static type extractors reading NonNullable<S["~standard"]["types"]>["input" | "output"]. |
import * as z from "zod";
import type { StandardSchemaV1 } from "@standard-schema/spec";
// Generic framework validator accepting any StandardSchemaV1-compliant schema
async function validateBody<S extends StandardSchemaV1>(
schema: S,
body: unknown,
): Promise<StandardSchemaV1.InferOutput<S>> {
let result = schema["~standard"].validate(body);
if (result instanceof Promise) result = await result;
if (result.issues) {
throw new Error(z.prettifyError(result));
}
return result.value;
}