What this does
Generates Zod validators from a JSON Schema, so the same contract can be enforced at runtime in TypeScript code. Each entry in $defs or definitions becomes a named constant, emitted before the schemas that use it, followed by the root schema and (optionally) the inferred TypeScript types.
import { z } from "zod";
export const Address = z.object({
city: z.string(),
});
export type Address = z.infer<typeof Address>;
export const User = z.object({
id: z.number().int().min(1),
email: z.email(),
address: Address.optional(),
});
export type User = z.infer<typeof User>;Keyword mapping
- Strings:
minLength,maxLength, andpatternbecome.min(),.max(), and.regex(); the formatsemail,uuid,uri,date-time,date,time,ipv4, andipv6become Zod's string formats. - Numbers:
integer,minimum,maximum,exclusiveMinimum,exclusiveMaximum, andmultipleOf. - Arrays:
minItems,maxItems, and tuples fromprefixItems. - Objects: properties not in
requiredare.optional();additionalProperties: falsebecomes.strict(), a schema there becomes.catchall(). - A type list that includes
nullbecomes.nullable(); other lists becomez.union().anyOfandoneOfbecome unions,allOfan intersection,enumaz.enum()or literal union. descriptionbecomes.describe().
Versions and recursion
Choose Zod 4 (the default) or Zod 3. They differ mainly in string formats: Zod 4 uses top-level helpers such as z.email(), while Zod 3 uses z.string().email(). Recursive definitions are emitted with z.lazy() and an explicit TypeScript type, which TypeScript needs because it cannot infer a type that refers to itself.
What is not expressed
The tool reports a warning under the output for keywords Zod cannot express directly:uniqueItems, not, if/then/else,patternProperties (accepted as a record without checking keys), and the exactly-one-match rule of oneOf. References to other files or URLs are never fetched and becomez.unknown(). Input is limited to 1 MB.
Privacy
The conversion runs in your browser. Your schema is never uploaded or stored.