@zod/core
This page is primarily intended for consumption by library authors who are building tooling on top of Zod.
What's in @zod/core
This 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:
For simplicity, the zod
and @zod/mini
packages re-export their @zod/core
dependency as z.core
, but you shouldn't rely on this.
Versioning
While Zod 4 is in beta, the @zod/core
package is published as latest
in the v0.x
range ("initial development" according to semver). Once the first stable release release of Zod 4, at which point v1.0.0
will be released.
Standard Schema
If you're building a library that accepts user-defined Zod schemas (say, an API framework) you first first look into Standard Schema. Zod implements the Standard Schema spec, which is a library-agnostic "standard interface" for schema libraries to expose a validation method and their inferred input/output types.
Dependencies
If you are building Zod-specific functionality (say, introspecting the schema) then Standard Schema won't be sufficient. In this case, you'll need a peer dependency on Zod.
I recommend the following versioning strategy for your library:
The peer dependency lets users "bring-their-own-Zod". As written this allows the user to use any 0.x.y
version of @zod/core
.
While you develop your library, you'll need to pick some version of Zod to use, in order to write your code. Use a dev dependency for this. This dev dependency ensures you fulfil the peer dependency requirement.
Schemas
The base class for all Zod schemas is $ZodType
. It accepts two generic parameters: Output
and Input
.
@zod/core
exports a number of subclasses that implement some common parsers. A union of all first-party subclasses is exported as z.$ZodTypes
.
All @zod/core
subclasses only contain a single property: _zod
. This property is an object containing the schemas internals. The goal is to make @zod/core
as extensible and unopinionated as possible. Other libraries can "build their own Zod" on top of these classes without @zod/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.
There are a number of subclasses of $ZodString
that implement various string formats. These are exported as z.$ZodStringFormatTypes
.
Checks
Every Zod schema contains an array of checks. These perform post-parsing refinements (and occasionally mutations) that do not affect the inferred type.
The base class for all Zod checks is $ZodCheck
. It accepts a single generic parameter T
.
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_lenth"
,"less_than"
,"string_format"
, etc.
.check()
— Contains the check's validation logic.
@zod/core
exports a number of subclasses that perform some common refinements. All first-party subclasses are exported as a union called z.$ZodChecks
.
You can use the ._zod.def.check
property to discriminate between these classes.
As with schema types, there are a number of subclasses of $ZodCheckStringFormat
that implement various string formats.
Use a nested switch
to discriminate between the different string format checks.
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
).
Errors
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
zod
package implements a subclass of$ZodError
calledZodError
with some additional convenience methods. - The
@zod/mini
package directly uses$ZodError
Issues
The issues
property corresponds to an array of $ZodIssue
objects. All issues extend the z.$ZodIssueBase
interface.
Zod defines the following issue subtypes:
For details on each type, refer to the implementation.
Future proofing
To future proof your library, you should always allow for new schema and check classes to be added in the future. If you are using switch statements to discriminate over union types, consider printing a warning when an unknown schema type is encountered.
If instead you throw
an error in the default case, your library will be unusable if/when new schemas types are added in the future. Best to print a warning and treat it as a "no-op" (or some other reasonable fallback behavior).
The same applies to unrecognized check types, string formats, etc.
If you are a schema author and think this page should include some additional guidance, please open an issue!