JSON → Zod

Generate a Zod schema from a JSON sample.

Private by design. Your input never leaves this browser. Conversions run locally on your device.

What this tool handles

  • Emits a Zod schema, with or without the import line.
  • Whole numbers become z.number().int() when integer inference is on.
  • Nested objects become nested z.object() calls.
  • The schema describes the sample you paste; it is not inferred from a wider dataset.

Example

JSON sample

{"id":1,"name":"Ada","active":true}

Zod schema

import { z } from 'zod';

export const RootSchema = z.object({
  id: z.number().int(),
  name: z.string(),
  active: z.boolean(),
});

export type Root = z.infer<typeof RootSchema>;

When you would use it

  • Seeding validation at an API boundary — Generate a schema from a real upstream response and parse with it inside the fetch wrapper, so a shape change fails at the boundary rather than three components later.
  • Validating a webhook or queue message — A captured delivery gives the first draft of the safeParse call in the handler, which you then tighten on the fields the handler actually reads.
  • A validator and a type from one sample — The exported z.infer alias is named after the schema with a trailing "Schema" removed, so UserSchema also gives you a User type and there is nothing to keep in step by hand.

Common questions

Are nested objects extracted into separate schemas?

No. Every level is inlined into a single expression, however deep the sample goes, and nothing named is declared below the root. Lift an AddressSchema out by hand if you want to reuse it.

Does it recognise emails, UUIDs or ISO dates?

No. Every string becomes a plain z.string() with no refinement: no .email(), no .uuid(), no .datetime(), and no min, max or length on strings, numbers or arrays. Those are the parts worth adding yourself.

How are optional and nullable fields told apart?

A key missing from some elements of a sample array gets .optional(), and a key seen as null in at least one record gets .nullable(). A key that was null in every record becomes z.null() on its own, since nothing else was ever observed.

Are unknown keys rejected?

No. A plain z.object() is emitted and neither .strict() nor .passthrough() is ever added, so extra keys follow the default Zod behaviour and are stripped instead of raising an issue.

Related tools

Browse all 25 tools