Generate a Zod runtime schema from any JSON sample, with z.infer type included.
Updated
Options
Input JSON
Zod schema
⌘EnterCopy schema
⌘KClear input
Quick start
How to generate a Zod schema from JSON
Paste a JSON sample to get a Zod schema you can drop straight into your codebase — with z.infer type alias.
Step 1
Paste JSON
Drop an API response or sample payload into the input pane. Two or more records improve optional-field detection.
Step 2
Tune the output
Choose schema name, whether to include the import line and z.infer type alias, and whether objects should .passthrough() unknown keys.
Step 3
Copy
Click Copy (or ⌘/Ctrl + Enter) to grab the Zod source. Everything runs locally — no upload, no telemetry.
In-depth guide
JSON to Zod — generate runtime schemas from sample data
Paste any JSON value — an API response, a config file, a sample payload — and get a Zod schema you can drop straight into your codebase. The shape inference runs locally in your browser; nothing is uploaded. The emitted code uses only stable Zod 3.x / 4.x primitives.
Why bother with a runtime schema?
TypeScript interfaces vanish at compile time. The moment an API drops a field, renames a key or sends a string where you expected a number, your app blows up at the use site with a mysterious "undefined is not a function".
A Zod schema validates the payload at the boundary — once, right after the fetch() — and either narrows the type or throws a precise error pointing at the bad field. You get the static type for free via z.infer<typeof schema>.
How the inference works
Parse the JSON via JSON.parse.
Walk the tree producing a "shape" for each value — primitive, array, object or union.
Merge sibling shapes (array elements, objects with overlapping key sets). Missing keys become .optional(). null + T becomes T.nullable(). Multiple non-null types become z.union([...]).
Emit a single z.object({...}) tree as plain TypeScript source.
What it can't infer (you add by hand)
Sample data tells us the shape, not the rules. After generating the baseline schema, add semantic refinements as needed:
.email(), .url(), .uuid() on strings that follow well-known formats.
.min(n) / .max(n) on lengths, counts and bounded numbers.
.regex(/^…$/) for IDs, phone numbers, postcodes.
z.enum([...]) for status fields where you know the closed set of values.
z.date() + .transform() when your wire format is an ISO string but you want a JS Date.
Tips for the best output
Paste multiple records when you can. A single sample marks every field required. Two samples with differing keys mark the difference .optional().
Mind numeric IDs. JSON has no int vs string distinction; phone numbers, postal codes and snowflake IDs are often JSON numbers but should be z.string() to preserve leading zeros and avoid precision loss above 2⁵³.
Use .passthrough() sparingly. Without it, Zod silently drops unknown keys on parse — that's usually what you want. Switch it on only if you're proxying a payload through unchanged.
When to use it vs alternatives
Use this tool for quick inspection, cleanup, conversion, and copy-paste debugging. Use your IDE formatter, schema tests, or CI checks when the same rule needs to be enforced across a repository.
Common pitfalls
Validate the output before committing it, especially when fixing almost-valid input.
Escaping, comments, trailing commas, and mixed encodings are the usual source of surprising results.
For production config, keep a copy of the original until the consuming system accepts the rewritten file.
Frequently asked questions
Is my JSON uploaded to a server?
No. Parsing, shape inference and Zod source emission all run entirely in your browser. The JSON you paste never leaves your device — there is no network call at any stage.
What Zod version does the output target?
The emitted code uses the stable API that ships in Zod 3.x and Zod 4 — `z.object`, `z.array`, `z.string`, `z.number`, `z.boolean`, `z.null`, `z.union`, `.optional()`, `.nullable()` and `.passthrough()`. These primitives have been stable since Zod 3.0 (released 2021).
How are optional fields detected?
If you paste a single object, every field is treated as required by default. If you paste an array of objects, fields that are present in some elements but missing in others are marked `.optional()`. You can also force every field to `.optional()` via the toggle.
How are nullable values handled?
When a value is `null` in one sample and a real type in another, the merged shape becomes `T.nullable()`. When the same key carries multiple non-null types (`string | number`), it becomes a `z.union([z.string(), z.number()])`.
Should I turn on .passthrough()?
Use it when you want Zod to allow unknown keys through `parse()`. By default the emitted schema does not call `.passthrough()`, which matches Zod's spec: "Z.object() ignores unknown keys by default" — extra keys won't fail parsing but will be stripped from the output.
Does it generate refinements like min/max/email?
No — refinements require semantic knowledge that isn't recoverable from a single JSON sample. Add `.min()`, `.email()`, `.url()`, `.regex()` etc. by hand after generation. The generator produces a structural baseline you can extend.
Can I use the output without TypeScript?
Yes. The emitted code is valid JavaScript when stripped of the optional `z.infer<typeof schema>` type alias (toggle that off). Zod itself works in pure JavaScript projects — only the inferred type lines require TS.
What's the difference vs json-schema-to-zod?
`json-schema-to-zod` consumes an existing JSON Schema document. This tool consumes raw JSON samples. If you already have a JSON Schema, the other approach is more precise (it preserves `format`, `minimum`, `enum`, etc.). If all you have is example data, this tool is the right starting point.
Keep exploring
More tools you'll like
Hand-picked utilities that pair well with the one you're on — all
free, client-side, and zero-signup.