Zod logo

JSON Schema

💎

新功能 — Zod 4 引入了一项新功能:原生 JSON Schema 转换。JSON Schema 是描述 JSON 结构的标准(使用 JSON)。它广泛用于 OpenAPI 定义以及为 AI 定义 结构化输出

¥New — Zod 4 introduces a new feature: native JSON Schema conversion. JSON Schema is a standard for describing the structure of JSON (with JSON). It's widely used in OpenAPI definitions and defining structured outputs for AI.

要将 Zod 模式转换为 JSON 模式,请使用 z.toJSONSchema() 函数。

¥To convert a Zod schema to JSON Schema, use the z.toJSONSchema() function.

import * as z from "zod";
 
const schema = z.object({
  name: z.string(),
  age: z.number(),
});
 
z.toJSONSchema(schema)
// => {
//   type: 'object',
//   properties: { name: { type: 'string' }, age: { type: 'number' } },
//   required: [ 'name', 'age' ],
//   additionalProperties: false,
// }

所有模式和检查都转换为最接近的 JSON 模式等效项。某些类型没有对应的类型,因此无法合理地表示。有关处理这些情况的更多信息,请参阅下面的 unrepresentable 部分。

¥All schema & checks are converted to their closest JSON Schema equivalent. Some types have no analog and cannot be reasonably represented. See the unrepresentable section below for more information on handling these cases.

z.bigint(); // ❌
z.int64(); // ❌
z.symbol(); // ❌
z.void(); // ❌
z.date(); // ❌
z.map(); // ❌
z.set(); // ❌
z.transform(); // ❌
z.nan(); // ❌
z.custom(); // ❌

字符串格式

¥String formats

Zod 将以下 Schema 类型转换为等效的 JSON Schema format

¥Zod converts the following schema types to the equivalent JSON Schema format:

// Supported via `format`
z.email(); // => { type: "string", format: "email" }
z.iso.datetime(); // => { type: "string", format: "date-time" }
z.iso.date(); // => { type: "string", format: "date" }
z.iso.time(); // => { type: "string", format: "time" }
z.iso.duration(); // => { type: "string", format: "duration" }
z.ipv4(); // => { type: "string", format: "ipv4" }
z.ipv6(); // => { type: "string", format: "ipv6" }
z.uuid(); // => { type: "string", format: "uuid" }
z.guid(); // => { type: "string", format: "uuid" }
z.url(); // => { type: "string", format: "uri" }

这些模式通过 contentEncoding 支持:

¥These schemas are supported via contentEncoding:

z.base64(); // => { type: "string", contentEncoding: "base64" }

所有其他字符串格式均通过 pattern 支持:

¥All other string formats are supported via pattern:

z.base64url();
z.cuid();
z.regex();
z.emoji();
z.nanoid();
z.cuid2();
z.ulid();
z.cidrv4();
z.cidrv6();

数字类型

¥Numeric types

Zod 将以下数字类型转换为 JSON Schema:

¥Zod converts the following numeric types to JSON Schema:

// number
z.number(); // => { type: "number" }
z.float32(); // => { type: "number", exclusiveMinimum: ..., exclusiveMaximum: ... }
z.float64(); // => { type: "number", exclusiveMinimum: ..., exclusiveMaximum: ... }
 
// integer
z.int(); // => { type: "integer" }
z.int32(); // => { type: "integer", exclusiveMinimum: ..., exclusiveMaximum: ... }

对象模式

¥Object schemas

默认情况下,z.object() 模式包含 additionalProperties: "false"。这准确描述了 Zod 的默认行为,因为普通的 z.object() 模式会剥离额外的属性。

¥By default, z.object() schemas contain additionalProperties: "false". This is an accurate representation of Zod's default behavior, as plain z.object() schema strip additional properties.

import * as z from "zod";
 
const schema = z.object({
  name: z.string(),
  age: z.number(),
});
 
z.toJSONSchema(schema)
// => {
//   type: 'object',
//   properties: { name: { type: 'string' }, age: { type: 'number' } },
//   required: [ 'name', 'age' ],
//   additionalProperties: false,
// }

"input" 模式下转换为 JSON Schema 时,additionalProperties 未设置。更多信息请参阅 io 文档

¥When converting to JSON Schema in "input" mode, additionalProperties is not set. See the io docs for more information.

import * as z from "zod";
 
const schema = z.object({
  name: z.string(),
  age: z.number(),
});
 
z.toJSONSchema(schema, { io: "input" });
// => {
//   type: 'object',
//   properties: { name: { type: 'string' }, age: { type: 'number' } },
//   required: [ 'name', 'age' ],
// }

相比之下:

¥By contrast:

  • z.looseObject() 永远不会设置 additionalProperties: false

    ¥z.looseObject() will never set additionalProperties: false

  • z.strictObject() 将始终设置 additionalProperties: false

    ¥z.strictObject() will always set additionalProperties: false

文件模式

¥File schemas

Zod 将 z.file() 转换为以下 OpenAPI 友好架构:

¥Zod converts z.file() to the following OpenAPI-friendly schema:

z.file();
// => { type: "string", format: "binary", contentEncoding: "binary" }

大小和 MIME 检查也表示为:

¥Size and MIME checks are also represented:

z.file().min(1).max(1024 * 1024).mime("image/png");
// => {
//   type: "string",
//   format: "binary",
//   contentEncoding: "binary",
//   contentMediaType: "image/png",
//   minLength: 1,
//   maxLength: 1048576,
// }

可空性

¥Nullability

Zod 将 JSON Schema 中的 undefined/null 转换为 { type: "null" }

¥Zod converts both undefined/null to { type: "null" } in JSON Schema.

z.null(); 
// => { type: "null" }
 
z.undefined(); 
// => { type: "null" }

类似地,nullable 通过与 null:: 的联合来表示。

¥Similarly, nullable is represented via a union with null::

z.nullable(z.string());
// => { oneOf: [{ type: "string" }, { type: "null" }] }

可选模式按原样表示,但它们带有 optional 注释。

¥Optional schemas are represented as-is, though they are decorated with an optional annotation.

z.optional(z.string());
// => { type: "string" }

配置

¥Configuration

第二个参数可用于自定义转换逻辑。

¥A second argument can be used to customize the conversion logic.

z.toJSONSchema(schema, {
  // ...params
})

以下是每个受支持参数的快速参考。下面将更详细地解释每个问题。

¥Below is a quick reference for each supported parameter. Each one is explained in more detail below.

interface ToJSONSchemaParams {
  /** The JSON Schema version to target.
 
   * - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
 
   * - `"draft-7"` — JSON Schema Draft 7 */
  target?: "draft-7" | "draft-2020-12";
 
  /** A registry used to look up metadata for each schema. 
 
   * Any schema with an `id` property will be extracted as a $def. */
  metadata?: $ZodRegistry<Record<string, any>>;
 
  /** How to handle unrepresentable types.
 
   * - `"throw"` — Default. Unrepresentable types throw an error
 
   * - `"any"` — Unrepresentable types become `{}` */
  unrepresentable?: "throw" | "any";
 
  /** How to handle cycles.
 
   * - `"ref"` — Default. Cycles will be broken using $defs
 
   * - `"throw"` — Cycles will throw an error if encountered */
  cycles?: "ref" | "throw";
 
  /* How to handle reused schemas.
 
   * - `"inline"` — Default. Reused schemas will be inlined
 
   * - `"ref"` — Reused schemas will be extracted as $defs */
  reused?: "ref" | "inline";
 
  /** A function used to convert `id` values to URIs to be used in *external* $refs.
 
   *    * Default is `(id) => id`.
   */
  uri?: (id: string) => string;
}

target

要设置目标 JSON 模式版本,请使用 target 参数。默认情况下,Zod 将以 2020-12 草案为目标。

¥To set the target JSON Schema version, use the target parameter. By default, Zod will target Draft 2020-12.

z.toJSONSchema(schema, { target: "draft-7" });
z.toJSONSchema(schema, { target: "draft-2020-12" });

metadata

如果你还没有阅读 元数据和注册表 页面,了解在 Zod 中存储元数据的上下文。

¥If you haven't already, read through the Metadata and registries page for context on storing metadata in Zod.

在 Zod 中,元数据存储在注册表中。Zod 导出一个全局注册表 z.globalRegistry,可用于存储常见的元数据字段,例如 idtitledescriptionexamples

¥In Zod, metadata is stored in registries. Zod exports a global registry z.globalRegistry that can be used to store common metadata fields like id, title, description, and examples.

import * as z from "zod";
 
// `.meta()` is a convenience method for registering a schema in `z.globalRegistry`
const emailSchema = z.string().meta({ 
  title: "Email address",
  description: "Your email address",
});
 
z.toJSONSchema(emailSchema);
// => { type: "string", title: "Email address", description: "Your email address", ... } 

所有元数据字段都会被复制到生成的 JSON Schema 中。

¥All metadata fields get copied into the resulting JSON Schema.

const schema = z.string().meta({
  whatever: 1234
});
 
z.toJSONSchema(schema);
// => { type: "string", whatever: 1234 }

unrepresentable

以下 API 无法在 JSON Schema 中表示。默认情况下,如果遇到这些情况,Zod 会抛出错误。尝试转换为 JSON Schema 是不合理的;你应该修改你的模式,因为它们在 JSON 中没有等效的模式。如果遇到任何这些情况,都会抛出错误。

¥The following APIs are not representable in JSON Schema. By default, Zod will throw an error if they are encountered. It is unsound to attempt a conversion to JSON Schema; you should modify your schemas as they have no equivalent in JSON. An error will be thrown if any of these are encountered.

z.bigint(); // ❌
z.int64(); // ❌
z.symbol(); // ❌
z.void(); // ❌
z.date(); // ❌
z.map(); // ❌
z.set(); // ❌
z.transform(); // ❌
z.nan(); // ❌
z.custom(); // ❌

默认情况下,如果遇到任何这些情况,Zod 都会抛出错误。

¥By default, Zod will throw an error if any of these are encountered.

z.toJSONSchema(z.bigint());
// => throws Error

你可以通过将 unrepresentable 选项设置为 "any" 来更改此行为。这会将任何不可表示的类型转换为 {}(相当于 JSON Schema 中的 unknown)。

¥You can change this behavior by setting the unrepresentable option to "any". This will convert any unrepresentable types to {} (the equivalent of unknown in JSON Schema).

z.toJSONSchema(z.bigint(), { unrepresentable: "any" });
// => {}

cycles

如何处理循环。如果 z.toJSONSchema() 在遍历模式时遇到循环,它将使用 $ref 表示。

¥How to handle cycles. If a cycle is encountered as z.toJSONSchema() traverses the schema, it will be represented using $ref.

const User = z.object({
  name: z.string(),
  get friend() {
    return User;
  },
});
 
z.toJSONSchema(User);
// => {
//   type: 'object',
//   properties: { name: { type: 'string' }, friend: { '$ref': '#' } },
//   required: [ 'name', 'friend' ],
//   additionalProperties: false,
// }

如果你想抛出错误,请将 cycles 选项设置为 "throw"

¥If instead you want to throw an error, set the cycles option to "throw".

z.toJSONSchema(User, { cycles: "throw" });
// => throws Error

reused

如何处理在同一模式中多次出现的模式。默认情况下,Zod 将内联这些模式。

¥How to handle schemas that occur multiple times in the same schema. By default, Zod will inline these schemas.

const name = z.string();
const User = z.object({
  firstName: name,
  lastName: name,
});
 
z.toJSONSchema(User);
// => {
//   type: 'object',
//   properties: { 
//     firstName: { type: 'string' }, 
//     lastName: { type: 'string' } 
//   },
//   required: [ 'firstName', 'lastName' ],
//   additionalProperties: false,
// }

你可以将 reused 选项设置为 "ref",以将这些模式提取到 $defs 中。

¥Instead you can set the reused option to "ref" to extract these schemas into $defs.

z.toJSONSchema(User, { reused: "ref" });
// => {
//   type: 'object',
//   properties: {
//     firstName: { '$ref': '#/$defs/__schema0' },
//     lastName: { '$ref': '#/$defs/__schema0' }
//   },
//   required: [ 'firstName', 'lastName' ],
//   additionalProperties: false,
//   '$defs': { __schema0: { type: 'string' } }
// }

override

定义一些自定义覆盖逻辑,请使用 override。提供的回调可以访问原始 Zod 模式和默认 JSON 模式。此函数应直接修改 ctx.jsonSchema

¥To define some custom override logic, use override. The provided callback has access to the original Zod schema and the default JSON Schema. This function should directly modify ctx.jsonSchema.

const mySchema = /* ... */
z.toJSONSchema(mySchema, {
  override: (ctx)=>{
    ctx.zodSchema; // the original Zod schema
    ctx.jsonSchema; // the default JSON Schema
 
    // directly modify
    ctx.jsonSchema.whatever = "sup";
  }
});

请注意,在调用此函数之前,不可表示的类型将抛出 Error 错误。如果你尝试为不可表示的类型定义自定义行为,则需要同时设置 unrepresentable: "any"override

¥Note that unrepresentable types will throw an Error before this functions is called. If you are trying to define custom behavior for an unrepresentable type, you'll need to use set the unrepresentable: "any" alongside override.

// support z.date() as ISO datetime strings
const result = z.toJSONSchema(z.date(), {
  unrepresentable: "any",
  override: (ctx) => {
    const def = ctx.zodSchema._zod.def;
    if(def.type ==="date"){
      ctx.jsonSchema.type = "string";
      ctx.jsonSchema.format = "date-time";
    }
  },
});

io

某些模式类型具有不同的输入和输出类型,例如 ZodPipeZodDefault 和强制转换的原语。默认情况下,z.toJSONSchema 的结果代表输出类型;改用 "io": "input" 提取输入类型。

¥Some schema types have different input and output types, e.g. ZodPipe, ZodDefault, and coerced primitives. By default, the result of z.toJSONSchema represents the output type; use "io": "input" to extract the input type instead.

const mySchema = z.string().transform(val => val.length).pipe(z.number());
// ZodPipe
 
const jsonSchema = z.toJSONSchema(mySchema); 
// => { type: "number" }
 
const jsonSchema = z.toJSONSchema(mySchema, { io: "input" }); 
// => { type: "string" }

注册表

¥Registries

将模式传递给 z.toJSONSchema() 将返回一个独立的 JSON 模式。

¥Passing a schema into z.toJSONSchema() will return a self-contained JSON Schema.

在其他情况下,你可能有一组 Zod 模式,希望使用多个相互链接的 JSON 模式来表示,例如写入 .json 文件并通过 Web 服务器提供服务。

¥In other cases, you may have a set of Zod schemas you'd like to represent using multiple interlinked JSON Schemas, perhaps to write to .json files and serve from a web server.

import * as z from "zod";
 
const User = z.object({
  name: z.string(),
  get posts(){
    return z.array(Post);
  }
});
 
const Post = z.object({
  title: z.string(),
  content: z.string(),
  get author(){
    return User;
  }
});
 
z.globalRegistry.add(User, {id: "User"});
z.globalRegistry.add(Post, {id: "Post"});

为此,你可以将 registry 传递给 z.toJSONSchema()

¥To achieve this, you can pass a registry into z.toJSONSchema().

重要 — 所有架构都应在注册表中注册一个 id 属性!任何没有 id 的 Schema 都将被忽略。

¥— All schemas should have a registered id property in the registry! Any schemas without an id will be ignored.

z.toJSONSchema(z.globalRegistry);
// => {
//   schemas: {
//     User: {
//       id: 'User',
//       type: 'object',
//       properties: {
//         name: { type: 'string' },
//         posts: { type: 'array', items: { '$ref': 'Post' } }
//       },
//       required: [ 'name', 'posts' ],
//       additionalProperties: false,
//     },
//     Post: {
//       id: 'Post',
//       type: 'object',
//       properties: {
//         title: { type: 'string' },
//         content: { type: 'string' },
//         author: { '$ref': 'User' }
//       },
//       required: [ 'title', 'content', 'author' ],
//       additionalProperties: false,
//     }
//   }
// }

默认情况下,$ref URI 是像 "User" 一样的简单相对路径。要使这些属性成为绝对 URI,请使用 uri 选项。此示例需要一个将 id 转换为完全限定 URI 的函数。

¥By default, the $ref URIs are simple relative paths like "User". To make these absolute URIs, use the uri option. This expects a function that converts an id to a fully-qualified URI.

z.toJSONSchema(z.globalRegistry, {
  uri: (id) => `https://example.com/${id}.json`
});
// => {
//   schemas: {
//     User: {
//       id: 'User',
//       type: 'object',
//       properties: {
//         name: { type: 'string' },
//         posts: {
//           type: 'array',
//           items: { '$ref': 'https://example.com/Post.json' }
//         }
//       },
//       required: [ 'name', 'posts' ],
//       additionalProperties: false,
//     },
//     Post: {
//       id: 'Post',
//       type: 'object',
//       properties: {
//         title: { type: 'string' },
//         content: { type: 'string' },
//         author: { '$ref': 'https://example.com/User.json' }
//       },
//       required: [ 'title', 'content', 'author' ],
//       additionalProperties: false,
//     }
//   }
// }

On this page