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
Set the name used for the schema constant and inferred type. A blank field uses Root. Click Generate Zod Schema to apply a name change.
Append .strict() to generated z.object schemas so Zod rejects extra keys. Click Generate Zod Schema to apply this option.
Generate now with the current JSON, root name and strict mode. Ctrl/⌘+Enter also generates.
Replace the input with a sample containing nested objects, arrays and null, then generate with the current name and strict mode.
Clear JSON, output and status. Keep the root name and strict mode. Ctrl/⌘+L within the tool also clears the root name.
Enter valid JSON. Generation runs 300 ms after typing stops; invalid JSON clears the output. Object, array and primitive roots are supported.
Zod Schema Output
Copy the complete displayed TypeScript snippet, including the Zod import, schema and inferred type. Empty output is not copied.

Enter JSON or load the example to generate a Zod schema.

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 import
  • const FooSchema = z.object({…}) — Schema definition
  • export 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:

GeneratedProblemChange to (Zod 4)
email: z.string()Any string passesz.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 passesz.string().nullable()
status: z.string()Any string passesz.enum(["active", "inactive"])
Field present in the sampleRequired, 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 becomes z.record(z.string(), z.unknown()).
  • null becomes z.null(). The generator does not add .nullable(). In an array of objects, a key that is null in the first item and a string in the second becomes z.union([z.null(), z.string()]).
  • Mixed arrays become a union. An array such as [{"a": 1}, 2], at the root or inside an object, gives z.array(z.union([z.number().int(), z.object({ a: z.number().int() })])). All objects in one array merge into a single z.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.