{}JSONLint.app

JSON to Python Converter

Generate Python classes from JSON data. Supports dataclasses, Pydantic, and TypedDict:

Loading...
Loading...

Generate Python Classes from JSON

This tool converts JSON data into type-annotated Python classes. Choose from dataclasses, Pydantic models, or TypedDict depending on your use case.

Output Formats

dataclass (Python 3.7+)

Standard library solution for data classes. Simple, no dependencies:

from dataclasses import dataclass
from typing import List, Optional

@dataclass
class User:
    id: int
    user_name: str
    email: str
    tags: List[str]
    profile: Optional[Profile] = None

Pydantic

Powerful data validation library, popular with FastAPI:

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

class User(BaseModel):
    id: int
    user_name: str = Field(..., alias="userName")
    email: str
    tags: List[str]
    
    class Config:
        populate_by_name = True

TypedDict

Type hints for dictionaries, useful for type checking without runtime overhead:

from typing import TypedDict, List

class User(TypedDict):
    id: int
    user_name: str
    email: str
    tags: List[str]

When to Use Each Format

FormatBest ForFeatures
dataclassGeneral purpose, no depsAuto __init__, __repr__, __eq__
PydanticAPI validation, FastAPIValidation, serialization, aliases
TypedDictType checking onlyDict compatibility, no overhead

Options Explained

snake_case conversion

Converts camelCase JSON keys to Python's preferred snake_case:

// JSON: "firstName"
# Python: first_name

For Pydantic, this adds Field(alias="...") to map between formats.

Optional for nulls

When enabled, null values become Optional[T] with a default of None.

Type Mapping

JSONPython
stringstr
integerint
floatfloat
booleanbool
nullOptional[T] or None
arrayList[T]
objectNested class

Using Generated Classes

With dataclass

import json

# Parse JSON
data = json.loads(json_string)
user = User(**data)

# Access fields
print(user.user_name)

# Convert back to dict
from dataclasses import asdict
user_dict = asdict(user)

With Pydantic

# Parse JSON directly
user = User.model_validate_json(json_string)

# Or from dict
user = User(**data)

# Convert to JSON
json_output = user.model_dump_json()

# With aliases (original JSON keys)
json_output = user.model_dump_json(by_alias=True)

Working with APIs

For comprehensive JSON handling in Python, see our Python JSON Guide which covers parsing, serialization, and common patterns.

Related Tools

Frequently Asked Questions

Should I use dataclass or Pydantic?

Use dataclass for simple data containers without validation needs. Use Pydantic when you need validation, serialization, or are building APIs with FastAPI. Pydantic adds ~2ms overhead per parse but catches errors early.

What Python version do I need?

Dataclasses require Python 3.7+. Pydantic v2 requires Python 3.8+. TypedDict requires Python 3.8+ (or typing_extensions for 3.7).

How do I handle nested objects?

The converter automatically generates separate classes for nested objects and uses them as type annotations. Dependencies are ordered correctly in the output.

Common Mistakes & Pro Tips

  • dataclass vs TypedDict vs dict are different toolsA `@dataclass` gives you a real class with `__init__`, attribute access (`obj.name`), and defaults; a `TypedDict` is just a type annotation over a plain `dict` (`obj["name"]`) with no runtime behavior; a raw `dict` has no typing at all. Choose dataclass when you instantiate objects, TypedDict when you're typing JSON you `json.loads` and access by key.
  • json.loads gives float, not int, for decimalsPython's `json` maps integers to `int` and any number with a decimal point or exponent to `float`. A sample value of `1.0` is inferred as `float`, while `1` is `int` — so if a field is sometimes whole and sometimes fractional, annotate it `float`. Use `parse_int`/`parse_float` hooks or `Decimal` if you need exact decimals (e.g. money).
  • Optional needs a default to actually be optional`Optional[str]` (i.e. `str | None`) only documents that the value may be `None`; it does not make the dataclass field optional. To allow omitting it you must give a default, like `name: Optional[str] = None`. Note that mutable defaults (lists, dicts) require `field(default_factory=list)`, never `= []`.
  • Reserved words and bad identifiers can't be field namesJSON keys like `class`, `from`, `import`, `lambda`, or keys with hyphens/spaces are invalid Python identifiers. For dataclasses you'll need to rename them (e.g. `class_` ) and remap during loading; TypedDict can use the functional form `Movie = TypedDict('Movie', {'class': str})` to keep the literal key.
  • Empty arrays and mixed arrays degrade to broad typesAn empty array `[]` carries no element type, so it's typed `List[Any]`; a heterogeneous array becomes `List[Any]` or a `Union`. Tighten these by hand to the real element type, e.g. `List[int]`, once you know the schema.

Frequently Asked Questions

How do I handle optional or nullable fields?

Type the field as `Optional[T]` (equivalently `T | None` on Python 3.10+) and give it a default of `None` so it can be omitted: `email: Optional[str] = None`. For a TypedDict, mark individual keys with `NotRequired[T]` (Python 3.11+ / typing_extensions) or split into a second `total=False` TypedDict. Remember `Optional` alone doesn't make a dataclass field skippable — the default does.

Do dataclasses validate types at runtime?

No — dataclasses store whatever you pass; type hints are not enforced, so `User(age="oops")` succeeds. If you want runtime validation and JSON parsing/coercion, use Pydantic (`BaseModel`), which checks and converts types, or add `__post_init__` checks manually. The standard `dataclasses` module is purely structural.

How do I convert the generated dataclass back to and from JSON?

`dataclasses.asdict(obj)` gives a dict you can pass to `json.dumps`. Going the other way, `MyClass(**json.loads(text))` works only for flat objects — nested dataclasses won't be reconstructed automatically. For nested structures use `pydantic`, `dacite`, or the `dataclasses-json` library, which rebuild the object tree for you.

Why are my JSON `snake_case` keys kept as-is?

Python's convention is already `snake_case`, so keys like `created_at` map cleanly to attributes without renaming. If your JSON uses `camelCase` (e.g. `createdAt`), the generator keeps that as the attribute name, which is unidiomatic — rename to `created_at` and use an alias (Pydantic `Field(alias=...)` or a custom decoder) to map back to the original JSON key.

Should I use `List`/`Dict` or `list`/`dict` in annotations?

Since Python 3.9 you can subscript the builtins directly (`list[str]`, `dict[str, int]`) and no longer need to import from `typing`. On 3.8 and earlier you must use `typing.List` / `typing.Dict`. Pick based on your minimum supported Python version; the builtins are now preferred.

Does this tool send my JSON anywhere?

No. Conversion happens locally in your browser, so the JSON you paste — including private payloads — is never transmitted to a server. You can use it offline once the page has loaded.