Zod / Pydantic Schema Converter
Paste a schema in Zod, Pydantic, JSON Schema or a TypeScript interface and get the other three, each with a list of the constraints that did not survive.
Nesting depth 3. Every output below was parsed back and compared with what you pasted; 10 differences came out of that check.
- Nesting depth
- 3
- Zod (TypeScript), characters
- 366
- Pydantic (Python), characters
- 445
- JSON Schema, characters
- 1,111
- TypeScript interface, characters
- 244
- Estimated tokens, JSON Schema form
- ≈ 278
- priority: was required, came back optional
- tags: nullable was nothing, came back true
- tags: a default of null appeared, which you did not set
- id: format was "uuid", came back nothing
- title: min was 1, came back nothing
- title: max was 120, came back nothing
- priority: was integer, came back number
- priority: min was 1, came back nothing
- priority: max was 5, came back nothing
- priority: the default 3 was lost
The reason a schema converter is worth having is not that writing the other three by hand is hard. It is that the four dialects are not equally expressive, and the places they disagree are silent. Zod's .min(1) has no home in a TypeScript interface. A TypeScript union of two object types has no home in any of the other three. Pydantic's gt is exclusive where JSON Schema's minimum is inclusive, so a careless conversion widens what you accept by exactly one value and nothing anywhere complains.
Why the output is parsed back
Because a converter that claims to be lossless is easy to write and impossible to trust. Every output above is read again by the parser for its own dialect and compared with your input, field by field, and the differences are printed underneath it. If the TypeScript block loses your length limits, you see two lines saying so here rather than finding out when a 300-character title reaches the database.
Which one to send to a model
The JSON Schema; the other three are for your own code. Structured output modes take JSON Schema, and the schema goes into the prompt on every request that uses it — so its size is a recurring cost, not a one-off, which is what the character counts above are for. A description on a field earns its tokens when it stops that field being filled with nonsense. A description on every field because a generator put one there does not.