Skip to content
Schema conversion

JSON Schema ⇄ Zod Converter

Generate a Zod schema from JSON Schema, or write JSON Schema back out from Zod code. Maps required to .optional(), plus enums, unions, nested objects, string formats and length constraints in both directions. Anything that cannot be converted is reported as a warning. Everything runs in your browser and the schema you paste is never sent anywhere.

Guide: How to use & features

  • Choose "JSON Schema → Zod" and paste a schema to get a `z.object({ ... })` definition plus a `z.infer` type alias.
  • Choose "Zod → JSON Schema" for the reverse. Leading `import` lines and `export const user =` are fine — the parser picks out the expression starting at `z.`.
  • Properties missing from `required` get `.optional()`, and in the reverse direction anything without `.optional()` is collected into `required`.
  • String details map both ways too: `format: "email"` becomes `.email()`, `minLength` becomes `.min()`.
  • Anything that cannot be converted, such as `$ref` or `allOf`, is reported as a warning under the output rather than silently producing a broken result.

FAQ: FAQ

  • How is this different from the JSON to Zod tool?

    The input is different. JSON to Zod infers types from a sample value such as an API response, so it cannot know which fields are required or what string formats apply. This tool takes JSON Schema itself, so constraints like required, enum, minLength and format:email carry through into the Zod chain (.optional() / .enum() / .min() / .email()). If you already have an OpenAPI or JSON Schema definition, this is the accurate path.
  • How do required and .optional() line up?

    The defaults are inverted between the two. JSON Schema treats a property as required only when it is listed in the required array, whereas Zod treats a property as required unless it carries .optional(). The converter absorbs that: going to Zod, properties missing from required get .optional(); coming back, properties without .optional() are collected into the required array.
  • Can it handle schemas that use $ref?

    References are not resolved. A $ref becomes z.any() and a warning is shown. If your schema factors shared definitions into $defs, either inline them before pasting or fix up that part of the generated output by hand. allOf is also reported, because an intersection cannot be expressed here — only the first subschema is converted.
  • Can I use the generated Zod schema for production validation?

    It works as a skeleton, but business rules that were never in the JSON Schema — allowed email domains, cross-field consistency — will not appear. Also note that a pattern becomes z.string().regex(), which can behave differently if the original regular expression is not ECMAScript-compatible. Always review the output before shipping it.

Use cases: Common use cases

  • Turn an OpenAPI definition into front-end types and validation

    The components.schemas section of OpenAPI is JSON Schema, so pasting it here gives you a Zod schema plus a z.infer type in one step — and keeps the server contract and client validation from drifting apart.

  • Export an existing Zod schema as an API contract

    If the Zod schema came first in your codebase, run the conversion the other way to produce JSON Schema you can drop into OpenAPI components or your docs.

  • Migrate hand-written validation to schema-driven checks

    When replacing a pile of if statements, an existing JSON Schema gives you a complete starting Zod schema — far fewer missed required fields and enums.

  • Make an AI-generated JSON Schema usable

    Paste a schema produced by an LLM and convert it into a Zod schema that actually compiles, giving you both static types and runtime validation.

Notes: Notes & limitations

  • $ref, allOf and conditionals are not expanded

    A $ref is not resolved and becomes z.any(); allOf converts only its first subschema. if/then/else and not are unsupported. All of these are surfaced as warnings under the output so you can fill in those parts by hand.

  • Zod → JSON Schema parses your code as text

    To keep everything in the browser, the code is never executed — it is parsed as text. z.object / z.array / z.union / z.enum / z.literal / z.record and the common method chains are supported, but a schema referenced through a variable, or an arbitrary function such as .refine(), cannot be represented in JSON Schema and is ignored.

  • Regular expressions in pattern are carried over verbatim

    A JSON Schema pattern becomes z.string().regex(), and the reverse puts the source back into pattern. JSON Schema permits regular expressions that are not ECMAScript-compatible, so a direct move can change behaviour.

  • Always review the generated output

    This tool produces a starting point for a migration. Business rules and cross-field consistency checks are not generated unless they were expressed in the original schema, so review the result before relying on it in production.

Articles for this tool

Recent Articles

Introduction
2026-08-06

Converting Between JSON Schema and Zod: How required Maps to .optional()

Inside a two-way converter that turns JSON Schema into a Zod schema and Zod code back into JSON Schema. Covers the inverted defaults between required and .optional(), the constraint mapping table, and how the Zod side is parsed without executing any code.

Use Case
2026-08-06

SQL Clause Order Reference: Why WHERE Can't See Your SELECT Alias

The order you write SQL clauses is not the order the database runs them. A reference for the logical execution order (FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT), why aliases fail in WHERE, when to use WHERE vs HAVING, and the MySQL/PostgreSQL differences that bite.

Use Case
2026-08-06

Unified Diff Format Reference: Reading @@ Hunks in git diff Output

How to read the unified diff format git produces: what the four numbers in @@ -12,7 +12,9 @@ mean, why a one-character edit shows as a whole-line replacement, the whitespace and line-ending traps, \ No newline at end of file, combined @@@ diffs on merges, and rename detection via similarity index.

Use Case
2026-08-06

UTC to JST Reference: The 9-Hour Offset, Cheat Sheet & Timezone Pitfalls

Convert between UTC and JST (Japan Standard Time) with a cheat sheet. Covers what Z and +09:00 mean in ISO 8601, when JavaScript date parsing silently shifts by 9 hours, MySQL/PostgreSQL timezone behavior, and why GitHub Actions cron always runs in UTC.

Use Case
2026-08-04

CREATE TABLE Reference: MySQL vs PostgreSQL vs SQLite Types & Constraints

A cross-database CREATE TABLE (DDL) reference with cheat sheets for data types, auto-increment keys (AUTO_INCREMENT / IDENTITY / rowid), foreign key ON DELETE behavior, and the CHECK constraint that MySQL silently ignores.

Introduction
2026-08-03

How CREATE TABLE Generation From a Visual Table Design Works | DDL Builder

A look inside DDL Builder, which turns a visually designed table into CREATE TABLE statements and an ER diagram. Covers the MySQL/PostgreSQL/SQLite type-mapping rules and the column-inference algorithm used for JSON samples.

Ad

Ad