Capítulo 50 de 61
Registries associate strongly-typed metadata with schema instances — z.globalRegistry (with .meta() as its convenience method) is the built-in one for common fields like title/description, and custom registries let you define your own metadata shape, optionally constrained to specific schema types.
z.registry<MetaType>(): creates a registry whose metadata must match MetaType; .add(schema, meta), .has(schema), .get(schema), .remove(schema), .clear() manage entries. z.registry() with no type argument acts as a plain schema collection with no metadata requirement.id is special: every registry (including the global one) throws if two schemas are registered with the same id..register(registry, meta): the one Zod method that returns the original schema instance rather than a new one — every other method (including .meta(), .describe()) is immutable and returns a new instance.z.globalRegistry: the built-in registry for { id?, title?, description?, deprecated?, [k: string]: unknown }; extend its type via TypeScript declaration merging (declare module "zod" { interface GlobalMeta { ... } })..meta({...}): convenience shortcut for .register(z.globalRegistry, {...}); calling it with no argument retrieves the schema's metadata. Metadata is tied to the specific instance — since Zod methods are immutable, a schema derived via .refine() etc. does not inherit the original's metadata..describe(text): shorthand for .meta({ description: text }); still available but .meta() is now the recommended general-purpose API.z.$output / z.$input: special type references usable inside a custom registry's metadata type to reference the associated schema's inferred output/input type (e.g. an examples: z.$output[] field).z.registry<MetaType, z.ZodString>() restricts what schema types can be added to the registry at all — attempting .add() with a non-matching schema type is a compile error.const myRegistry = z.registry<{ description: string }>();
const mySchema = z.string();
myRegistry.add(mySchema, { description: "A cool schema!" });
myRegistry.get(mySchema); // => { description: "A cool schema!" }
// .register() returns the ORIGINAL schema, unlike every other Zod method
const named = z.object({
name: z.string().register(myRegistry, { description: "The user's name" }),
});
// z.globalRegistry + .meta()
const emailSchema = z.email().meta({
id: "email_address", title: "Email address", description: "Your email address",
});
emailSchema.meta(); // => { id: "email_address", title: "Email address", ... }
// metadata does NOT carry over to derived schemas
const A = z.string().meta({ description: "A cool string" });
const B = A.refine(_ => true);
B.meta(); // => undefined
// metadata type referencing the schema's inferred output
type MyMeta = { examples: z.$output[] };
const examplesRegistry = z.registry<MyMeta>();
examplesRegistry.add(z.string(), { examples: ["hello", "world"] });
// constraining which schema types a registry accepts
const stringOnlyRegistry = z.registry<{ description: string }, z.ZodString>();
stringOnlyRegistry.add(z.number(), { description: "nope" }); // compile error
.register()/immutability interaction, and type-level constraints on registry contents..refine()/.extend()/other chained methods: it doesn't — metadata is keyed to the exact schema instance, and immutable methods always return a new instance without it..register() is the one exception to Zod's "everything returns a new instance" rule — use it specifically when you want to attach metadata without creating a fresh schema reference..meta() as the last step in a schema's construction, after all .refine()/.extend()/etc. calls, or the metadata won't be reachable from the final schema.z.$output/z.$input in their metadata type are the pattern for type-safe example values, default-generators, or anything else that needs to reference "the type this schema produces.".meta() fields flow directly into z.toJSONSchema() output.z.globalRegistry used for multi-file JSON Schema generation.