JSON to Zod Schema
Generate Zod validation schemas from JSON data instantly. Handles nested objects, arrays, nullable fields, and optional properties. Runs in your browser.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
Output Format
The generator outputs a complete TypeScript snippet including:
import { z } from “zod”— Zod importconst FooSchema = z.object({…})— Schema definitionexport type Foo = z.infer<typeof FooSchema>— Inferred TypeScript type
Common Use Cases
- API validation: Generate schemas from API response examples to validate real responses at runtime.
- Form validation: Convert a form’s expected data shape into Zod schemas for use with react-hook-form or similar.
- Config files: Define and validate configuration objects loaded from JSON files.
- Type safety: Pair with TypeScript to get both runtime validation and static type inference from a single schema.
Example
With the root name User, this sample:
{
"id": 42,
"email": "alice@example.com",
"price": 19.9,
"tags": ["admin", "beta"],
"metadata": null,
"orders": [
{ "sku": "A1", "qty": 2 },
{ "sku": "B7", "qty": 1, "note": "gift" }
]
}
produces:
import { z } from "zod";
const UserSchema = z.object({
id: z.number().int(),
email: z.string(),
price: z.number(),
tags: z.array(z.string()),
metadata: z.null(),
orders: z.array(z.object({
sku: z.string(),
qty: z.number().int(),
note: z.string().optional(),
})),
});
export type User = z.infer<typeof UserSchema>;
note is optional because only one of the two orders has it. The output uses only calls that work in both Zod 3 and Zod 4.
Refining the Generated Schema
A sample shows one value per field, so the generator cannot know your rules. Check these points before you use the schema:
| Generated | Problem | Change to (Zod 4) |
|---|---|---|
email: z.string() | Any string passes | z.email() (Zod 3: z.string().email()) |
qty: z.number().int() | Correct only if the value is always a whole number. price: 10 in the sample also gives .int(), and then 10.5 fails with “expected int” | z.number() for prices; add .min(0) or .positive() |
metadata: z.null() | Only null passes | z.string().nullable() |
status: z.string() | Any string passes | z.enum(["active", "inactive"]) |
| Field present in the sample | Required, even if the API sometimes leaves it out | .optional() |
Use .parse() where a failure should stop the program (configuration at startup): it throws a ZodError. Use .safeParse() for API responses and user input: it returns { success: false, error } and you handle the error yourself.
Limits
- Types come from one sample. An empty array becomes
z.array(z.unknown()), and an empty object becomesz.record(z.string(), z.unknown()). nullbecomesz.null(). The generator does not add.nullable(). In an array of objects, a key that isnullin the first item and a string in the second becomesz.union([z.null(), z.string()]).- Mixed arrays become a union. An array such as
[{"a": 1}, 2], at the root or inside an object, givesz.array(z.union([z.number().int(), z.object({ a: z.number().int() })])). All objects in one array merge into a singlez.object, so the union has one object member. - No string formats or limits. Emails, URLs, dates, and UUIDs are all
z.string().
FAQ
What is Zod?
Zod is a TypeScript-first schema declaration and validation library. It lets you define the shape of your data with a schema, then validate data against that schema at runtime. It's widely used for API response validation, form validation, and configuration parsing.
How does the generator infer types?
The generator inspects each JSON value: strings become z.string(), booleans become z.boolean(), integers become z.number().int(), floats become z.number(), null becomes z.null(), arrays become z.array(), and objects become z.object(). For arrays of objects, keys present in only some items are marked as optional.
What is strict mode?
In strict mode, .strict() is appended to every z.object() call. This causes Zod to reject input objects that contain keys not defined in the schema. Without strict mode, extra keys are silently ignored (the default Zod behavior).
Does this generate production-ready schemas?
The generated schemas are a strong starting point. You should review and refine them — for example, adding .min()/.max() constraints on strings and numbers, converting nullable fields to .nullable().optional(), or splitting nested schemas into separate named constants.
Is my JSON data sent anywhere?
No. All processing happens in your browser. Your JSON data never leaves your device.