+
+ name |
+
+ Must be specified as an id property in a registry.
+ |
+
+
+ nameStrategy |
+
+ The `title` is an unrelated metadata property. Only `id` is used for refs.
+ |
+
+
+ basePath |
+
+ ✅ Supported
+ |
+
+
+ $refStrategy |
+
+ Only schemas specified in a registry will be pulled out as a ref.
+ |
+
+
+ effectStrategy |
+
+ The `ZodEffects` class no longer exists. Refinements are stored internally by schemas; they are supported. Transforms are represented with `ZodTransform` and are not supported.
+ |
+
+
+ dateStrategy |
+
+ The `z.date()` API is not supported. Use `z.iso.date()` to represent string-encoded dates.
+ |
+
+
+ emailStrategy |
+
+ This always uses `format: "email"`. If you specify a custom `pattern`, it will be added to the schema with `pattern`.
+ |
+
+
+ base64Strategy |
+
+ This always uses `contentEncoding: "base64"`. If your JSON Schema parser doesn't support `contentEncoding`, don't use `z.string().regex()` instead of `z.base64()`.
+ |
+
+
+ definitionPath |
+
+ ✅ Supported
+ |
+
+
+ target |
+
+ Out of scope
+ |
+
+
+ strictUnions |
+
+ ❌ Should never be necessary
+ |
+
+
+ definitions |
+
+ Registries make this obsolete.
+ |
+
+
+ errorMessages |
+
+ ❌ Not supported
+ |
+
+
+ markdownDescription |
+
+ ❌ Not supported
+ |
+
+
+ patternStrategy |
+
+ ❌ Not supported
+ |
+
+
+ applyRegexFlags |
+
+ Support is planned.
+ |
+
+
+ pipeStrategy |
+
+ Always uses the output schema.
+ |
+
+
+
+ removeAdditionalStrategy
+
+ allowedAdditionalProperties
+
+ rejectedAdditionalProperties
+ |
+
+ Additional properties is left unset by default. Use a `strict` schema if you want to disallow additional properties.
+ |
+
+
+ override |
+
+ Out of scope
+ |
+
+
+ postProcess |
+
+ Out of scope
+ |
+
+
*/}
+
+## Registries
+
+Passing a schema into `z.toJSONSchema()` will return a *self-contained* JSON Schema.
+
+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. To achieve this, you can pass a [registry](/metadata#registries) into `z.toJSONSchema()`.
+
+```ts
+import * as z from "zod";
+
+const User = z.interface({
+ name: z.string(),
+ get posts(){
+ return z.array(Post);
+ }
+});
+
+const Post = z.interface({
+ title: z.string(),
+ content: z.string(),
+ get author(){
+ return User;
+ }
+});
+
+z.globalRegistry.add(User, {id: "User"});
+z.globalRegistry.add(Post, {id: "Post"});
+```
+
+The schemas above both have an `id` property registered in `z.globalRegistry`. To convert these to JSON Schema, pass the entire registry into `z.toJSONSchema()`.
+
+```ts
+z.toJSONSchema(z.globalRegistry);
+// => {
+// schemas: {
+// User: {
+// id: 'User',
+// type: 'object',
+// properties: {
+// name: { type: 'string' },
+// posts: { type: 'array', items: { '$ref': 'Post' } }
+// },
+// required: [ 'name', 'posts' ]
+// },
+// Post: {
+// id: 'Post',
+// type: 'object',
+// properties: {
+// title: { type: 'string' },
+// content: { type: 'string' },
+// author: { '$ref': 'User' }
+// },
+// required: [ 'title', 'content', 'author' ]
+// }
+// }
+// }
+```
+
+> Any schema with an `id` property in the registry will be extracted into `schemas`.
+
+By default the `$ref` URIs are 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.
+
+```ts
+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' ]
+// },
+// Post: {
+// id: 'Post',
+// type: 'object',
+// properties: {
+// title: { type: 'string' },
+// content: { type: 'string' },
+// author: { '$ref': 'https://example.com/User.json' }
+// },
+// required: [ 'title', 'content', 'author' ]
+// }
+// }
+// }
+```
diff --git a/packages/docs/content/meta.json b/packages/docs/content/meta.json
new file mode 100644
index 0000000000..31f30f1130
--- /dev/null
+++ b/packages/docs/content/meta.json
@@ -0,0 +1,22 @@
+{
+ "root": true,
+ "pages": [
+ "---Beta---",
+ "v4/index",
+ "v4/changelog",
+ "---Documentation---",
+ "index",
+ "basics",
+ "api",
+ "error-customization",
+ "error-formatting",
+ "metadata",
+ "json-schema",
+ "ecosystem",
+ "---Packages---",
+ "packages/zod",
+ "packages/mini",
+ "packages/json",
+ "packages/core"
+ ]
+}
diff --git a/packages/docs/content/metadata.mdx b/packages/docs/content/metadata.mdx
new file mode 100644
index 0000000000..ba6bb0a2a3
--- /dev/null
+++ b/packages/docs/content/metadata.mdx
@@ -0,0 +1,206 @@
+---
+title: "Metadata and registries"
+---
+
+import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
+import { Callout } from "fumadocs-ui/components/callout"
+
+{/* > Zod 4+ provides native `.toJSONSChema()` functionality that leverages registries to generate idiomatic JSON Schema from Zod. Refer to the [JSON SChema docs](/json-schema) page for more information. */}
+
+It's often useful to associate a schema with some additional *metadata* for documentation, code generation, AI structured outputs, form validation, and other purposes.
+
+## Registries
+
+Metadata in Zod is handled via *registries*. Registries are collections of schemas, each associated with some *strongly-typed* metadata. To create a simple registry:
+
+```ts
+import * as z from "zod";
+
+const myRegistry = z.registry<{ description: string }>();
+```
+
+To register, lookup, and remove schemas from this registry:
+
+```ts
+const mySchema = z.string();
+
+myRegistry.add(mySchema, { description: "A cool schema!"});
+myRegistry.has(mySchema); // => true
+myRegistry.get(mySchema); // => { description: "A cool schema!" }
+myRegistry.remove(mySchema);
+```
+
+TypeScript enforces that the metadata for each schema matches the registry's **metadata type**.
+
+```ts
+myRegistry.add(mySchema, { description: "A cool schema!" }); // ✅
+myRegistry.add(mySchema, { description: 123 }); // ❌
+```
+
+### `.register()`
+
+> **Note** — This method is special in that it does not return a new schema; instead, it returns the original schema. No other Zod method does this! That includes `.meta()` and `.describe()` (documented below) which return a new instance.
+
+Schemas provide a `.register()` method to more conveniently add it to a registry.
+
+```ts
+const mySchema = z.string();
+
+mySchema.register(myRegistry, { description: "A cool schema!" });
+// => mySchema
+```
+
+This lets you define metadata "inline" in your schemas.
+
+```ts
+const mySchema = z.object({
+ name: z.string().register(myRegistry, { description: "The user's name" }),
+ age: z.number().register(myRegistry, { description: "The user's age" }),
+})
+```
+
+