JSON to Zod Schema
Generate a Zod validation schema and TypeScript type from a JSON document.
Related Tools
Generate TypeScript interfaces or type aliases from JSON.
Validate JSON against a JSON Schema with JSON-pointer error paths.
Generate Python dataclasses from a JSON document.
Beautify and pretty-print JSON with configurable indentation.
Generate Go structs with JSON tags from a JSON document.
Generate a Java POJO class with getters and setters from a JSON document.
Documentation
What is JSON to Zod?
This tool turns a JSON sample into a Zod schema — a runtime validator plus a statically-inferred TypeScript type, generated from a single declaration. It's built for validating untrusted data (API responses, form submissions, webhook payloads) where a plain TypeScript interface can't help because interfaces vanish at runtime.
How it works
The same type-inference pass used across DevFormats' JSON converters walks the sample and builds a tree of object, array, and primitive nodes. Each nested object becomes its own z.object({...}) schema bound to a const NameSchema, printed before any schema that references it, plus a matching export type Name = z.infer<typeof NameSchema>. A field whose sample value was null gets .nullable() appended to its base schema rather than being made optional — those are different constraints in Zod, and the tool picks the one that actually matches what you observed.
Features
- Nested objects become their own named
z.object()schema, referenced by name from the parent - Arrays are typed with
z.array(...)using the inferred element schema - Each schema exports its
z.infer'd TypeScript type alongside it, so you get validation and types from one source - Null sample values map to
.nullable(), not silently dropped or widened toany - Non-identifier keys are safely quoted in the generated object literal
Example
Input: { "id": 101, "username": "alice_dev", "isActive": true, "signupBonus": null, "address": { "city": "Berlin", "zipCode": "10115" }, "tags": ["admin", "beta"] }
Output:
import { z } from 'zod';
export const AddressSchema = z.object({
city: z.string(),
zipCode: z.string(),
});
export type Address = z.infer<typeof AddressSchema>;
export const RootSchema = z.object({
id: z.number(),
username: z.string(),
isActive: z.boolean(),
signupBonus: z.unknown().nullable(),
address: AddressSchema,
tags: z.array(z.string()),
});
export type Root = z.infer<typeof RootSchema>;Common errors
A field the tool couldn't classify from a single sample (or one that was null) becomes z.unknown() — that will pass validation for anything, so tighten it manually once you know the real type. An empty array in the sample produces z.array(z.unknown()) since there's no element to infer from. Remember .nullable() accepts null but not a missing key — use .optional() as well if the field can be absent entirely.
Best practices
Use z.infer instead of hand-writing a parallel interface, so your runtime schema and compile-time type can never drift apart. Validate at the boundary — right where the JSON enters your app (fetch response, request handler) — and let the inferred type flow inward from there instead of re-validating deeper in your code.
Frequently Asked Questions
Why generate a Zod schema instead of a plain TypeScript interface?▾
A TypeScript interface only checks shapes at compile time — it disappears at runtime. A Zod schema validates real data (an API response, form input) at runtime and can derive the exact same TypeScript type via z.infer, so you get both a runtime check and a static type from one definition.
How are nullable fields handled?▾
A field whose sample value is null is generated as .nullable() on its base schema, matching Zod's own nullable API rather than making the field optional (missing), which is a different constraint.
Does this handle nested objects?▾
Yes — each nested object gets its own named z.object() schema plus an inferred type, referenced by name from the parent schema, so deeply nested JSON produces multiple readable schema declarations instead of one giant inline object.
What Zod version does the output target?▾
The generated code uses standard Zod v3/v4-compatible API (z.object, z.string, z.array, z.infer) with no version-specific syntax, so it should drop into any recent Zod install.