JSON to Pydantic Model

Generate a Pydantic model from a JSON document.

JSON Input
Pydantic Model Output
Pydantic Model output appears here

Related Tools

Documentation

What is JSON to Pydantic?

This tool converts a JSON sample into Pydantic BaseModel classes — Python models that both describe a shape and validate real data against it at runtime, which is why they're the default choice for FastAPI request/response bodies and for parsing any untrusted JSON.

How it works

Nested JSON objects each become their own class Name(BaseModel), printed child-first. Field names are converted from the JSON key to snake_case, matching Python convention. When that conversion changes the name — a camelCase JSON key like isActive becoming is_active — the generator adds Field(alias="isActive") so the model still accepts and serializes the exact original wire key while your Python code reads idiomatically. A field whose sample value was null becomes Optional[T] with a default of None — distinct from a field that's simply missing from the JSON, which can't be detected from one sample. A field name that collides with a Python keyword (like class or from) gets a trailing underscore.

Features

  • Automatic camelCase-to-snake_case field renaming with a matching Field(alias=...) so the wire format is unaffected
  • Nullable sample values map to Optional[T] = None, not silently dropped
  • Nested objects and arrays (List[T]) supported at any depth
  • Only imports Field and Any when the generated code actually needs them
  • Compatible with both Pydantic v1 and v2 — no version-specific syntax

Example

Input: { "id": 101, "username": "alice_dev", "isActive": true, "signupBonus": null, "address": { "city": "Berlin", "zipCode": "10115" }, "tags": ["admin", "beta"] }

Output:

from typing import Any, List, Optional
from pydantic import BaseModel, Field


class Address(BaseModel):
    city: str
    zip_code: str = Field(alias="zipCode")


class Root(BaseModel):
    id: int
    username: str
    is_active: bool = Field(alias="isActive")
    signup_bonus: Optional[Any] = Field(alias="signupBonus", default=None)
    address: Address
    tags: List[str]

Common errors

A null sample value becomes Optional[Any] — Pydantic will accept literally anything for that field until you narrow it to a real type. Remember that Field(alias=...) means the model only accepts input under the alias by default; if you also need attribute-style construction using the Python name, set populate_by_name = True (v2) or allow_population_by_field_name = True (v1) in your model config.

Best practices

Use model_config = ConfigDict(populate_by_name=True) (Pydantic v2) if your codebase constructs models directly from Python kwargs as well as from JSON, so both the snake_case name and the camelCase alias work as input. Replace Optional[Any] fields with a concrete union or type as soon as you know what the field can actually hold — leaving it as Any defeats the point of validating the payload at all.

Frequently Asked Questions

Why Pydantic instead of a plain dataclass?

A dataclass only describes shape — it does nothing at runtime to check that the data you actually received matches. Pydantic validates real data (an API response, request body) against the model and raises a clear error if it doesn't match, which is why it's the default choice for FastAPI request/response models and any code parsing untrusted JSON.

Why do some fields have Field(alias=...)?

JSON keys are often camelCase; Python convention is snake_case. When a field name would change from the original JSON key, the generator adds Field(alias="originalKey") so the model still accepts and serializes the exact original key over the wire while your Python code reads idiomatically.

How are nullable fields handled?

A field whose sample value is null becomes Optional[T] with a default of None, matching how Pydantic represents an optional field — distinct from a field that's simply absent from the JSON, which the generator can't detect from a single sample.

Does this target Pydantic v1 or v2?

The generated code (BaseModel, Field(alias=...)) works on both v1 and v2 — it doesn't use v2-only syntax like model_config or the newer validator decorators, so it drops into either version without changes.