Skip to content

Generate Python dataclasses from JSON

Convert JSON into Python dataclasses with modern type hints, snake_case attribute names and optional fields defaulting to None.

  • Runs in your browser
  • Files are never uploaded
  • Free, no account
JSON to Python dataclasses
Paste a real API response and get types that match its actual shape: nested objects become named types, keys missing from some array elements become optional, and values that vary become unions.

The name given to the outermost type.

Your JSON never leaves this tab — check it yourself—

Starting the network probe…

The counter above wraps fetch, XMLHttpRequest and navigator.sendBeacon in this tab and counts every call. It does not block anything — it just reports.

Two ways to verify independently

  1. Turn off Wi-Fi or enable airplane mode, then use the tool. It keeps working, because the page is already fully loaded.
  2. Open your browser devtools, switch to the Network tab, clear it, and run the tool. No new row appears.

Why this matters

In 2025 researchers found that popular online formatters had retained tens of thousands of user-submitted snippets — JSONFormatter.org and CodeBeautify together exposed roughly 80,000 saved documents, many containing live cloud credentials, private keys and internal database connection strings, because “format this” quietly meant “upload this”. A separate incident exposed roughly 3.5 million user PDFs on a document-conversion service. The only structural fix is not sending the data in the first place: this site is served under a Content-Security-Policy whose connect-src contains no third-party origin, so a request off this device cannot be made even by accident.

What you get

One @dataclass per distinct nested object, emitted child-first so the file reads top-down, with modern type hints: built-in generics (list[str], not List[str]) and the X | None union syntax. The file opens with from __future__ import annotations, which makes all annotations lazy and means forward references resolve regardless of class order.

Target is Python 3.10 or later. For 3.8 and 3.9, swap the built-in generics for their typing equivalents and X | None for Optional[X].

Field names

JSON keys are converted to snake_case, which is what PEP 8 asks for and what the rest of your code will expect. Two things happen automatically:

  • A name that collides with a Python keyword gets a trailing underscore: class becomes class_, from becomes from_.
  • Whenever the attribute name differs from the JSON key, the original key is written in a comment on the same line, so you can see what to map.

Required fields come first — and why they have to

Python raises TypeError: non-default argument follows default argument at class definition time if a field without a default appears after one with a default. Optional fields are therefore emitted last, with = None. If you reorder them by hand, keep that rule or the module will not import.

One related trap the generator avoids by never emitting one: a mutable default. tags: list[str] = [] is an error in a dataclass, because the same list would be shared by every instance. If you add a default for a list or dict, use field(default_factory=list).

Dataclasses do not deserialise nested JSON

This surprises people, so it is worth stating clearly. Order(**data) works for a flat object. For a nested one, order.customer will be a plain dict, not a Customer — the type hint is not enforced and nothing constructs the child. Three ways to fix it:

ApproachCostBest for
Write a from_dict classmethod per classManual, explicit, no dependencyA handful of classes
dacite.from_dict(Order, data)One small dependency, keeps the dataclassesMost cases
Switch to Pydantic BaseModelBigger dependency, but validation and coercion includedAPI boundaries

If you are already using Pydantic, converting is close to mechanical: replace @dataclass with a class X(BaseModel) declaration and delete the decorator. The field annotations carry over unchanged.

Types that need a second look

  • Timestamps arrive as str. Convert with datetime.fromisoformat, which since 3.11 handles the trailing Z.
  • Money arrives as float. Change it to Decimal and make sure the API sends it as a string, or you inherit binary-float rounding.
  • A field that is always one of a few strings should become an Enum or a Literal[...].
  • A dict keyed by ID generates one attribute per key in your sample. Replace the whole class with dict[str, Thing].

Questions

Which Python version does the output target?

Python 3.10 and later. It uses built-in generics (`list[str]` rather than `List[str]`) and the `X | None` union syntax, and includes `from __future__ import annotations` so the forward references between classes resolve regardless of definition order.

What happens to a key that is not a valid identifier?

It is converted to snake_case, and a trailing underscore is added if the result collides with a Python keyword (`class` becomes `class_`). The original JSON key is preserved in a comment on the same line so you can wire up an alias.

Will these classes deserialise JSON automatically?

No. `SomeClass(**data)` works for a flat object, but nested dataclasses need construction by hand or a library such as dacite, pydantic or mashumaro. The generated file gives you the shape; the parsing strategy is yours.

Why do optional fields come last?

Because a dataclass field with a default cannot precede one without — Python raises a TypeError at class definition time. Required fields are emitted first, then optionals with `= None`.