These are the docs for Zod 4, which is currently in beta. Go to Zod 3 docs 👉
Zod logo

For library authors

This page is primarily intended for consumption by library authors who are building tooling on top of Zod.

If you are a library author and think this page should include some additional guidance, please open an issue!

Do I need to depend on Zod?

First things first, make sure you need to depend on Zod at all.

If you're building a library that accepts user-defined schemas to perform black-box validation, you may not need to integrate with Zod specifically. Instead look into Standard Schema. It's a shared interface implemented by most popular validation libraries in the TypeScript ecosystem (see the full list), including Zod.

This spec works great if you accept user-defined schemas and treat them like "black box" validators. Given any compliant library, you can extract inferred input/output types, validate inputs, and get back a standardized error.

If you need Zod specific functionality, read on.

How to configure peer dependencies?

Any library built on top of Zod should include "zod" in "peerDependencies". This lets your users "bring their own Zod".

// package.json
{
  // ...
  "peerDependencies": {
    "zod": "^3.25.0"
  }
}

During development, you need to meet your own peer dependency requirement, to do so, add "zod" to your "devDependencies" as well. You'll need to use zod@next until zod@3.25.0 is stably released.

// package.json
{
  "peerDependencies": {
    "zod": "^3.25.0"
  },
  "devDependencies": {
    "zod": "next"
  }
}

How to support Zod 4?

To support Zod 4, update the minimum version for your "zod" peer dependency to ^3.25.0.

// package.json
{
  // ...
  "peerDependencies": {
    "zod": "^3.25.0"
  }
}

Starting with v3.25.0, Zod 4 is available at a /v4 subpath.

import * as z4 from "zod/v4/core";

Library code should not import from the package root ("zod")! Instead, import from the version-specific subpaths: "zod/v3" and "zod/v4/core". This way, your code is future-proofed against major version bumps down the line.

How to support Zod 3 and Zod 4 simultaneously?

Starting in v3.25.0, the package contains copies of both Zod 3 and Zod 4 at their respective subpaths. This makes it easy to support both versions simultaneously.

import * as z3 from "zod/v3";
import * as z4 from "zod/v4/core";
 
type Schema = z3.ZodTypeAny | z4.$ZodType;
 
function acceptUserSchema(schema: z3.ZodTypeAny | z4.$ZodType) {
  // ...
}

To differentiate between Zod 3 and Zod 4 schemas at runtime, check for the "_zod" property. This property is only defined on Zod 4 schemas.

import type * as z3 from "zod/v3";
import type * as v4 from "zod/v4/core";
 
declare const schema: z3.ZodTypeAny | v4.$ZodType;
 
if ("_zod" in schema) {
  schema._zod.def; // Zod 4 schema
} else {
  schema._def; // Zod 3 schema
}

How to support Zod and Zod Mini simultaneously?

Your library code should only import from zod/v4/core. This sub-package defines the interfaces, classes, and utilities that are shared between zod/v4 and zod/v4-mini.

// library code
import * as z from "zod/v4/core";
 
export function acceptObjectSchema<T extends z.$ZodObject>(schema: T){
  // parse data
  z.parse(schema, { /* somedata */});
  // inspect internals
  schema._zod.def.shape;
}

By building against the shared base interfaces, you can reliably support both sub-packages simultaneously. This function can accept both zod/v4 and zod/v4-mini schemas.

// user code
import { acceptObjectSchema } from "your-library";
 
// Zod 4
import * as z from "zod/v4";
acceptObjectSchema(z.object({ name: z.string() }));
 
// Zod 4 Mini
import * as zm from "zod/v4-mini";
acceptObjectSchema(zm.object({ name: zm.string() }))

Refer to the Zod Core page for more information on the contents of the core sub-library.

On this page