Overview
Paste a JSON sample and get back a ready-to-paste Zod schema — or a TypeScript interface or type alias, your choice — with nested objects, arrays, unions and null handled. The generator is honest about what a single sample can and cannot prove, and it emits code that actually parses: object keys that are not valid identifiers are quoted, not dropped into syntax errors.
How It Works
Paste JSON into the left pane; the generated code appears live on the right. Use the Root Interface Name field to set the top-level type's name (letters, digits and underscores only). The mode switch selects between Interface, Type and Zod Schema output; Prettify JSON re-indents messy input; Copy Code takes the result. Nothing is uploaded — parsing and generation both run in the page.
Step-by-Step Usage Guide
- Paste a representative JSON sample into the input pane.
- Name the root type in the Root Interface Name field.
- Pick Zod Schema for runtime validation code, or Interface / Type for a static type only.
- Copy the generated code into your project, then review optionality and coercion by hand — a sample cannot decide those for you.
Technical Specifications & Standards
The reason this tool exists is the gap between TypeScript's compile time and everything else. JSON.parse returns a value the compiler can only see as any, so a type annotation near the parse call describes a shape nobody has checked; a Zod schema describes the same shape as runtime-checked data, and the generated code's last line — export type X = z.infer<typeof XSchema> — derives the static type from the schema so the two cannot drift apart. The generator's inference rules, each verified by unit test: strings, numbers and booleans map to z.string(), z.number() and z.boolean(); null becomes z.null(); nested objects become nested z.object() calls (and named interfaces in TypeScript mode); an empty array becomes z.array(z.unknown()) because an empty sample proves nothing about its elements; an array with mixed element types becomes z.array(z.union([...])) of the distinct element schemas rather than silently trusting the first element. In TypeScript mode the same union logic produces (number | string)[], and arrays of objects get their element types named from the singularised field path — users becomes User[]. Two engineering details are worth knowing because cheap generators get them wrong. Object keys that are not valid identifiers — content-type, 2fa — are emitted quoted in both Zod and TypeScript output; unquoted, they are syntax errors in both languages, which you can verify in any console. And identical object shapes in an array share one generated type instead of producing duplicate interfaces. The limits are inherent to the input, not the implementation: a single sample can prove presence, never absence, so every observed key is required and nothing gets .optional(); a JSON sample contains no defaults and no strings-that-should-be-numbers, so z.coerce must be a deliberate human decision after generation; and two objects with different keys in one array produce a union of shapes rather than a merged guess.
Targeted Use Cases
- Typing a third-party API response before writing the client code that consumes it.
- Bootstrapping form validation from the payload a backend actually sends.
- Generating the schema and z.infer pair so runtime checks and compile-time types stay in sync.
- Turning a config file's sample into both documentation (interface) and enforcement (Zod).
Notes & Gotchas
- Feed the fattest sample you have: unions and nested shapes are inferred from what the sample contains, and missing keys are invisible.
- After generating, decide optionality deliberately — every key in a JSON sample was present, but that proves nothing about the next response.
- Choose z.coerce yourself where form or query data arrives as strings; the generator emits z.number() for JSON numbers, which is correct for JSON and wrong for form input.
- Keep the schema as the source of truth and rely on the generated z.infer type, instead of maintaining a separate interface by hand.
Frequently Asked Questions
Why is every field required in the generated schema?
A single JSON sample can only show keys that were present. Optionality — “sometimes missing” — is information about many responses, not one, so the generator marks nothing optional and leaves that decision to you.
What happens with an array containing different types?
It becomes z.array(z.union([…])) over the distinct element schemas — numbers and strings produce z.union([z.number(), z.string()]) — and in TypeScript mode, (number | string)[]. An empty array degrades to z.array(z.unknown()) because the sample proves nothing.
Why are some object keys quoted in the output?
Keys that are not valid JavaScript identifiers — content-type, 2fa — must be quoted in both a Zod object and a TypeScript interface, otherwise the generated file is a syntax error. The generator quotes exactly those keys and leaves plain identifiers bare.
Interface, Type or Zod Schema — which mode should I pick?
Zod Schema when the data must be validated at runtime (API responses, user input); its z.infer line gives you the matching static type. Interface or Type when you only need compile-time documentation for data you already trust, such as a checked-in config.