JSON to Pydantic Models
Generate Pydantic v2 models from a JSON sample, with nested classes, Optional detection across array items and safe field names. Runs in your browser.
Private by design: everything you enter is processed in your browser. It is not sent to our servers.
How to use
- Paste a JSON sample: an object, or an array of objects that all describe the same thing.
- Set the name of the top-level model and choose Optional[X] or X | None style.
- Copy the generated Pydantic v2 code into your project.
- Check the notes under the result: they tell you when field names were changed and aliases were added.
Worked example
A user record with a null value, a nested address and a list of orders where one order has an extra key.
JSON sample
{
"id": 1,
"name": "Ada",
"email": null,
"tags": ["a", "b"],
"address": { "city": "Pune", "zip": "411001" },
"orders": [
{ "sku": "x", "qty": 2, "note": null, "coupon": "A1" },
{ "sku": "y", "qty": 3.5, "note": "gift" }
]
}Generated models
from typing import Any, Optional
from pydantic import BaseModel
class OrdersItem(BaseModel):
sku: str
qty: float
note: Optional[str] = None
coupon: Optional[str] = None
class Address(BaseModel):
city: str
zip: str
class Model(BaseModel):
id: int
name: str
email: Optional[Any] = None
tags: list[str]
address: Address
orders: list[OrdersItem]
email is only ever null in the sample, so it becomes Optional[Any]. note and coupon are Optional because they are null or missing in some orders. qty is float because one order has 3.5. Orders become their own OrdersItem class.
How it works
The generator walks the JSON and infers a type for every value: str, int, float, bool, None, list[…] and nested objects (each nested object becomes its own class, named after its key). Booleans are never treated as integers, and if a field is sometimes int and sometimes float it becomes float.
When the sample is an array of objects, all elements are merged into one class. A key that is missing from some elements, or that is null in some, becomes Optional with a default of None. A field with truly different types becomes Union[…] (or X | Y).
Field names are made valid Python identifiers (snake_case, keywords get a trailing underscore, names that clash with Pydantic’s model_ attributes are prefixed). Whenever the name changes, the field gets Field(alias="original-key") so validation still accepts the original JSON key, as described in the Pydantic documentation.
The output uses Pydantic v2 style (BaseModel and Field from pydantic) with built-in generics such as list[str]. Nested classes are written before the classes that use them so the file runs top to bottom.
Common errors
Invalid JSON: …- Fix the syntax first (quotes, commas, brackets). The JSON Formatter style rules apply: double quotes only, no trailing commas.
The sample must be a JSON object, or a non-empty array of objects.- Wrap a bare value in an object, or give an array whose elements are all objects.
The model name must be a valid Python class name.- Use letters and digits, for example “User” or “OrderResponse”.
Input is too large (limit 1,000,000 characters).- Use a smaller representative sample.
Limits
- Types come from the sample only. A field that is always a string in your sample but sometimes a number in production will be typed str.
- Strings that look like dates, UUIDs or emails stay str; no datetime, UUID or constraint types are guessed.
- An empty list becomes list[Any] because there is nothing to learn the item type from.
- Keys that differ only in case or punctuation can collide after renaming; the generator appends underscores to keep names unique.
- Arrays that mix objects with scalars are not merged into one class.
Privacy
Your JSON is analysed in your browser and never sent anywhere. Share links include the JSON only if it is short. No account is needed, no cookies are set and no analytics run. See thePrivacy Policy. The “Copy share link” button puts your settings after the “#” in the address; browsers do not send that part to servers, and the page’s canonical address never includes it.
FAQ
Why Optional[Any] for a field that is always null?
A sample that only contains null gives no information about the real type, so Any is the honest answer. Replace it once you know the type.
Does it support Pydantic v1?
No, the output targets Pydantic v2 (it uses Field(alias=…) and built-in generics).
Why did my camelCase keys get aliases?
Python fields are conventionally snake_case, so userId becomes user_id with alias="userId" so incoming JSON still validates.
Should I trust the generated types?
Treat them as a first draft. Review the Optional and Union choices against your real data and API documentation.
Related
Embed this tool
Paste this snippet into your own page or docs to show the tool inline. The embedded view works the same way (everything runs in the visitor’s browser) and carries a small link back to MakeTools.
Sources
- Pydantic: Models – checked 2026-10-14
- Pydantic: Fields (aliases) – checked 2026-10-14
Page last updated 2026-10-14. Written by Prajyot Mulik; see the editorial policy.