JSON Schema → Pydantic
Convert JSON Schema to Pydantic v2 model code, in your browser. Paste schema, get a ready-to-paste Python class. Useful for LLM structured-output workflows.
Enter input above to see the result.
From schema to Python model
JSON Schema and Pydantic are the two main ways to describe a structured object — JSON Schema is the lingua-franca for OpenAPI specs, LLM function-calling, and structured outputs; Pydantic is Python's de-facto data-validation library. Pretty often you have one and you need the other. This tool does the conversion in one direction: paste a JSON Schema, get a Pydantic class you can drop into a Python file.
Scenarios that send you here
- LLM structured outputs. OpenAI's
response_formatand Anthropic's tool-use both take a JSON Schema. After you've designed and tested the schema, you usually want a Pydantic model to validate and access fields in Python. - OpenAPI client generation. An OpenAPI spec gives you JSON Schema for each request/response body; this is a quick way to get matching Pydantic models without pulling a full code-generator.
- Schema → Python migrations. You've inherited a system that uses JSON Schema for validation and you want to move it to Pydantic. Paste each schema, get a starting class, refine.
- Quick scaffolding. You sketched the shape in JSON in a notebook; turn it into a real model with one paste.
- Config file validation. Your application loads a YAML or JSON config at startup and you want runtime validation. Define the shape as JSON Schema once, paste it here, and you get a Pydantic model that rejects bad config with clear error messages instead of a silent KeyError three layers deep.
- Database fixture typing. Test suites that load JSON fixtures can validate them on import by running them through a generated Pydantic model — catching shape mismatches before the test even starts, rather than debugging a cryptic assertion failure mid-run.
Type mappings and what gets generated
type: objectwithproperties+required— generates a nested BaseModel class.type: arraywithitems— generatesList[X].- Primitives:
string→str,integer→int,number→float,boolean→bool,null→None. formaton string:date-time→datetime,email→EmailStr,uri/url→HttpUrl,uuid→UUID.enum→Literal[...];const→Literal[X].oneOf/anyOf→Union[...]; a null variant folds intoOptional[...].type: ["string", "null"]arrays →Optional[str].description→Field(..., description=...).default→ field default.minimum/maximum/minLength/maxLength→Field(ge=..., le=..., min_length=..., max_length=...).- Field names that aren't valid Python identifiers (hyphens, leading digits, keywords) are sanitised, and an
alias=is added to preserve the original wire name. The model is configured withpopulate_by_name=Trueso both work. - Nested objects become nested classes, named after the field if no
titleis provided. $defs/definitionsare emitted as separate classes.
Unsupported schema features
- External
$ref(URL refs). Local refs to$defswork. patternProperties. Emits a TODO comment.additionalPropertieswith a schema. Emits a TODO comment.- Multi-base
allOfcomposition. Single-elementallOfis unwrapped. - Custom validators based on
pattern— emit the field but skip the regex. Add a Pydantic@field_validatorafter pasting if you need it.
v1 vs v2 and naming pitfalls
- Pydantic v2 vs v1. Default output is v2 (current). Switch via the dropdown if you're on a v1 codebase. Big differences:
Field(...)for required,model_configreplacesclass Config:, deprecated validator decorators. - Output is a starting point, not the final word. Review it. Especially for complex unions, recursive types, and anything with custom validation rules.
- Names matter. The "Root class name" field controls the top-level class name. Sub-classes are named after their
titleproperty when present, otherwise after the field that contains them. - Required vs Optional in v2. A required field with no default uses
...:name: str = Field(...). Optional fields default toNoneand are wrapped inOptional[T]. - Nested objects. A schema with nested
propertiesblocks generates one class per object. Inner classes reference each other via forward refs, so declaration order matters if you rearrange the output. - Array constraints.
minItemsandmaxItemson arrays becomeField(min_length=..., max_length=...)on the list field, keeping your API contract enforced at parse time.
Running the User sample end to end
Load the built-in User sample — id, name, email required, an age with minimum: 0, and a tags array defaulting to [] — and it emits a ready-to-paste Pydantic class. Because email carries "format": "email" it becomes EmailStr; the minimum turns into Field(ge=0); the array becomes List[str] = []; and the three required fields get ... (required) while optional ones default to None. Flip the Pydantic v1/v2 switch and only the details that differ between versions change — e.g. how aliases and config are declared.
Types, unions, nesting, and validation keywords
How are JSON Schema types mapped? integer→int, number→float, string→str, boolean→bool. String formats upgrade the type: date-time→datetime, date→date, email→EmailStr, uri→HttpUrl, uuid→UUID, and the right imports are added automatically.
What happens to enums and unions? An enum becomes Literal[...] of its values; oneOf/anyOf becomes Union[...], and if null is one of the options it collapses to Optional[...]. A type: ["string", "null"] pair also becomes Optional[str].
Does it handle nested objects? Yes — every nested object schema is pulled out into its own BaseModel subclass, emitted before the model that references it so the file is valid Python top-to-bottom. $defs/definitions are generated too.
What about validation keywords and odd field names? minimum/maximum map to ge/le, minLength/maxLength to min_length/max_length, and description flows into Field(description=...). A property name that isn't a valid Python identifier gets a safe name plus an alias (and the matching populate-by-name config). Unsupported bits like patternProperties are marked with a # TODO rather than silently dropped. It all runs in your browser.