Zod Core
Source URL: https://zod.dev/packages/core
Zod Core
Section titled “Zod Core”Copy markdown
This sub-package exports the core classes and utilities that are consumed by Zod and Zod Mini. It is not intended to be used directly; instead it’s designed to be extended by other packages. It implements:
import * as z from "zod/v4/core";
// the base class for all Zod schemas z.$ZodType;
// subclasses of $ZodType that implement common parsers z.$ZodString z.$ZodObject z.$ZodArray // ...
// the base class for all Zod checks z.$ZodCheck;
// subclasses of $ZodCheck that implement common checks z.$ZodCheckMinLength z.$ZodCheckMaxLength
// the base class for all Zod errors z.$ZodError;
// issue formats (types only) {} as z.$ZodIssue;
// utils z.util.isValidJWT(...);The base class for all Zod schemas is $ZodType. It accepts two generic parameters: Output and Input.
export class $ZodType<Output = unknown, Input = unknown> { _zod: { /* internals */} }zod/v4/core exports a number of subclasses that implement some common parsers. A union of all first-party subclasses is exported as z.$ZodTypes.
export type $ZodTypes = | $ZodString | $ZodNumber | $ZodBigInt | $ZodBoolean | $ZodDate | $ZodSymbol | $ZodUndefined | $ZodNullable | $ZodNull | $ZodAny | $ZodUnknown | $ZodNever | $ZodVoid | $ZodArray | $ZodObject | $ZodUnion // $ZodDiscriminatedUnion extends this | $ZodIntersection | $ZodTuple | $ZodRecord | $ZodMap | $ZodSet | $ZodLiteral | $ZodEnum | $ZodPromise | $ZodLazy | $ZodOptional | $ZodDefault | $ZodTemplateLiteral | $ZodCustom | $ZodTransform | $ZodNonOptional | $ZodReadonly | $ZodNaN | $ZodPipe // $ZodCodec extends this | $ZodSuccess | $ZodCatch | $ZodFile;Inheritance diagram
Section titled “Inheritance diagram”All zod/v4/core subclasses only contain a single property: _zod. This property is an object containing the schemas internals. The goal is to make zod/v4/core as extensible and unopinionated as possible. Other libraries can “build their own Zod” on top of these classes without zod/v4/core cluttering up the interface. Refer to the implementations of zod and zod/mini for examples of how to extend these classes.
The _zod internals property contains some notable properties:
.def— The schema’s definition : this is the object you pass into the class’s constructor to create an instance. It completely describes the schema, and it’s JSON-serializable..def.type— A string representing the schema’s type, e.g."string","object","array", etc..def.checks— An array of checks that are executed by the schema after parsing.
.input— A virtual property that “stores” the schema’s inferred input type..output— A virtual property that “stores” the schema’s inferred output type..run()— The schema’s internal parser implementation.
If you are implementing a tool (say, a code generator) that must traverse Zod schemas, you can cast any schema to $ZodTypes and use the def property to discriminate between these classes.
export function walk(_schema: z.$ZodType) { const schema = _schema as z.$ZodTypes; const def = schema._zod.def; switch (def.type) { case "string": { // ... break; } case "object": { // ... break; } } }There are a number of subclasses of $ZodString that implement various string formats. These are exported as z.$ZodStringFormatTypes.
export type $ZodStringFormatTypes = | $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodJWTAs the Zod Core schema classes have no methods, there are top-level functions for parsing data.
import * as z from "zod/v4/core";
const schema = new z.$ZodString({ type: "string" }); z.parse(schema, "hello"); z.safeParse(schema, "hello"); await z.parseAsync(schema, "hello"); await z.safeParseAsync(schema, "hello");Every Zod schema contains an array of checks. These perform post-parsing refinements (and occasionally mutations) that do not affect the inferred type.
const schema = z.string().check(z.email()).check(z.min(5)); // => $ZodString
schema._zod.def.checks; // => [$ZodCheckEmail, $ZodCheckMinLength]The base class for all Zod checks is $ZodCheck. It accepts a single generic parameter T.
export class $ZodCheck<in T = unknown> { _zod: { /* internals */} }The _zod internals property contains some notable properties:
.def— The check’s definition : this is the object you pass into the class’s constructor to create the check. It completely describes the check, and it’s JSON-serializable..def.check— A string representing the check’s type, e.g."min_length","less_than","string_format", etc.
.check()— Contains the check’s validation logic.
zod/v4/core exports a number of subclasses that perform some common refinements. All first-party subclasses are exported as a union called z.$ZodChecks.
export type $ZodChecks = | $ZodCheckLessThan | $ZodCheckGreaterThan | $ZodCheckMultipleOf | $ZodCheckNumberFormat | $ZodCheckBigIntFormat | $ZodCheckMaxSize | $ZodCheckMinSize | $ZodCheckSizeEquals | $ZodCheckMaxLength | $ZodCheckMinLength | $ZodCheckLengthEquals | $ZodCheckProperty | $ZodCheckMimeType | $ZodCheckOverwrite | $ZodCheckStringFormatYou can use the ._zod.def.check property to discriminate between these classes.
const check = {} as z.$ZodChecks; const def = check._zod.def;
switch (def.check) { case "less_than": case "greater_than": // ... break; }As with schema types, there are a number of subclasses of $ZodCheckStringFormat that implement various string formats.
export type $ZodStringFormatChecks = | $ZodCheckRegex | $ZodCheckLowerCase | $ZodCheckUpperCase | $ZodCheckIncludes | $ZodCheckStartsWith | $ZodCheckEndsWith | $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodJWT;Use a nested switch to discriminate between the different string format checks.
const check = {} as z.$ZodChecks; const def = check._zod.def;
switch (def.check) { case "less_than": case "greater_than": // ... case "string_format": { const formatCheck = check as z.$ZodStringFormatChecks; const formatCheckDef = formatCheck._zod.def;
switch (formatCheckDef.format) { case "email": case "url": // do stuff } } break; }You’ll notice some of these string format checks overlap with the string format types above. That’s because these classes implement both the $ZodCheck and $ZodType interfaces. That is, they can be used as either a check or a type. In these cases, both ._zod.parse (the schema parser) and ._zod.check (the check validation) are executed during parsing. In effect, the instance is prepended to its own checks array (though it won’t actually exist in ._zod.def.checks).
// as a type z.email().parse("[[email protected]](https://zod.dev/cdn-cgi/l/email-protection)");
// as a check z.string().check(z.email()).parse("[[email protected]](https://zod.dev/cdn-cgi/l/email-protection)")The base class for all errors in Zod is $ZodError.
For performance reasons, $ZodError does not extend the built-in Error class! So using instanceof Error will return false.
- The
zodpackage implements a subclass of$ZodErrorcalledZodErrorwith some additional convenience methods. - The
zod/minisub-package directly uses$ZodError
export class $ZodError<T = unknown> implements Error { public issues: $ZodIssue[]; }The issues property corresponds to an array of $ZodIssue objects. All issues extend the z.$ZodIssueBase interface.
export interface $ZodIssueBase { readonly code?: string; readonly input?: unknown; readonly path: PropertyKey[]; readonly message: string; }Zod defines the following issue subtypes:
export type $ZodIssue = | $ZodIssueInvalidType | $ZodIssueTooBig | $ZodIssueTooSmall | $ZodIssueInvalidStringFormat | $ZodIssueNotMultipleOf | $ZodIssueUnrecognizedKeys | $ZodIssueInvalidUnion | $ZodIssueInvalidKey | $ZodIssueInvalidElement | $ZodIssueInvalidValue | $ZodIssueCustom;For details on each type, refer to the implementation.