AOT compilation
For hot validation paths, Zod can compile a schema into a specialized validator ahead of time, with identical results and identical errors.
Across a 55-schema benchmark the median speedup is 2.4x. It scales with how much work the schema does per parse, because what compilation removes is per-node dispatch and allocation rather than the checks themselves:
| schema | speedup |
|---|---|
z.array(z.string()), 100 items | ~14x |
z.array(z.object({…})), 50 items | ~9x |
| 20-key object | ~9x |
| nested object | ~4.5x |
| discriminated union | ~4x |
| 5-key object | ~2.5x |
z.string().min(3).max(64).regex(…) | ~2.8x |
bare z.string() | none |
A schema whose entire body is one typeof has no dispatch to remove, so compiling it buys nothing. Everything built out of such schemas still benefits — leaves are inlined into their parent's compiled code.
There are two ways to opt in.
z.compile()
Compiles a single schema eagerly and returns a clone with the fast path installed.
The clone is a regular Zod schema — .parse(), .safeParse(), type inference, Standard Schema integration, and composition all work as usual. The original schema is unchanged.
One thing to keep in mind: methods that derive a new schema (.refine(), .extend(), .optional(), .meta(), …) return uncompiled schemas. Compile the final schema, not an intermediate:
import "zod/compile"
Enables compilation globally. Every schema constructed after this import is compiled automatically on its first parse.
Module evaluation order matters: schemas constructed before the import are not affected. Place the import at the top of your application entry point.
Compilation is lazy (first parse), so intermediate schemas created during builder chains cost nothing extra.
Error parity
The compiled fast path is a happy-path validator. When an input fails validation — or requires anything the fast path doesn't support — Zod transparently falls back to the standard parser, which produces the exact same ZodError as the uncompiled schema. There is no separate compiled error path to drift out of sync.
Two consequences worth knowing:
- Invalid inputs pay for both the fast path and the fallback. If your workload is dominated by invalid inputs, compilation won't help (it also won't change any behavior).
- Refinements and transforms may run twice on invalid input — once in the fast path, once in the fallback. They run exactly once on valid input, and never more than twice.
Unsupported schemas
Compilation is sync and forward-only. z.compile() throws if the schema can't be fully modeled:
ZodCompileAsyncError— the schema contains an async refinement, transform, or check.ZodCompileUnsupportedError— the schema uses a construct the fast path can't reproduce exactly:z.xor(), whose exactly-one-match rule needs every branch to reject for the same reason the standard parser would.- Checks with custom
whenconditions. - A recursive schema, which needs the standard parser to resolve reference cycles in the input.
- Coercion (
z.coerce.*), which the fast path does not model. .catch()given a callback. A callback receives issues finalized against the caller's error map, which compiled code never sees..catch(value)with a constant compiles normally.
Inside containers (objects, arrays, tuples, records, intersections), an unsupported child doesn't prevent compilation — the child runs on the standard parser while the surrounding structure stays compiled.
Under global mode, schemas that fail to compile silently keep using the standard parser. There is no behavioral difference — only the speedup is lost. For this reason, avoid enabling global mode in a library on behalf of your users; leave the choice to the application.
Encode operations (z.encode(), codec "backward" direction) and async parsing always use the standard parser.
Content Security Policy
Compilation uses new Function, which is unavailable in CSP/no-eval environments. Global mode automatically stands down when jitless is set:
Calling z.compile() directly is treated as an explicit opt-in and throws ZodCompileUnsupportedError if code generation is unavailable.