What is JSON to Python conversion?
JSON to Python conversion generates Python data models — @dataclass definitions — from a sample JSON document, so you can load that data into typed objects instead of passing around raw dictionaries. Dataclasses, introduced in Python 3.7 via PEP 557, are chosen over plain dictionaries or TypedDict because they give the model a real constructor, equality, a readable repr, and dataclasses.asdict for serialization. The generator infers a type hint for every field, distinguishing int from float, mapping text to str and true or false to bool, turning arrays into list[...] with the right element type, and creating a separate dataclass for each nested object. Keys missing from some records become Optional, and keys that are not valid Python identifiers are handled safely. JSON Formatter Pro generates the code entirely in your browser, so the JSON you paste is never uploaded. Paste a representative sample and copy ready-to-use, PEP 585-annotated dataclasses into your project.
Worked example: JSON → Python
How JSON values map to Python types
| JSON value | Python type |
|---|---|
| string | str |
| integer | int |
| fractional number | float |
| true / false | bool |
| null | Any |
| array | list[T] |
| object | a @dataclass |
| key absent in some records | Optional[T] |
Complete Guide to Generating Python Dataclasses from JSON
Almost every Python program that talks to an HTTP API starts the same way: `response.json()` hands back a `dict`, and from that moment the shape of the data lives only in your head. Each `payload["profile"]["timezone"]` is a string key your editor cannot autocomplete, mypy and pyright cannot check, and no refactoring tool can rename safely. Typing the response once, at the boundary, is what makes the rest of the module something a type checker can genuinely reason about.
A JSON to Python dataclass generator reads one sample JSON document and emits the Python classes that describe its shape. Every JSON object becomes a class decorated with `@dataclass`; nested objects become their own classes, referenced by name; and each key becomes an annotated attribute — `str`, `int`, `float`, `bool`, `list[...]`, or `Optional[...]` where a null or a missing key was observed. What comes back is an instantiable record with a generated constructor, `__repr__`, `__eq__` and `dataclasses.asdict`, rather than the untyped dictionary `json.loads` returns. The practical difference is tooling: a dictionary offers an editor nothing to autocomplete and a type checker nothing to verify, so a field renamed upstream surfaces as a runtime `KeyError` instead of a static error. Generating the classes from a response you actually received, rather than writing them by hand from documentation, keeps the model honest about what the endpoint really sends.
JSON to Python Dataclass Generator Pro does exactly that, in your browser, with nothing to install and no signup.
How to Convert JSON to Python Dataclasses Online
- Paste a Real API Response: Paste your JSON into the left editor or upload a `.json` file. Malformed input is reported with its line and column before any class is generated.
- Read the Generated Classes: The output panel renders `@dataclass` definitions — the root class first, with every nested object extracted into its own class below it.
- Copy or Download: Click Copy to paste the classes straight into a module, or Download to save them as a `converted.py` file.
A Worked Example: One Response In, Typed Classes Out
Below is the exact output for a small but realistic payload: a user record containing a nested object, a list of records where one field is present on only some of them, and a header-style key that is not a legal Python attribute name.
Input JSON
{
"id": 481,
"username": "ada",
"rating": 4.75,
"content-type": "application/json",
"profile": {
"city": "London",
"timezone": "Europe/London"
},
"posts": [
{ "id": 7, "title": "Analytical Engine", "views": 3200 },
{ "id": 9, "title": "Note G", "views": 118, "pinned": true }
]
} Generated Python
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class Root:
id: int
username: str
rating: float
content_type: str = field(metadata={"json": "content-type"})
profile: Profile
posts: list[Post]
@dataclass
class Post:
id: int
title: str
views: int
pinned: Optional[bool]
@dataclass
class Profile:
city: str
timezone: str Four inference decisions in that output are worth pointing out. `rating` is a `float` while `id` and `views` are `int`, because only one of them carried a decimal point. `profile` was lifted into its own `Profile` class instead of being inlined. The two elements of `posts` were merged into a single `Post` class covering the union of their keys, and because `pinned` appears on only one of them it is typed `Optional[bool]` — the ragged-payload case hand-written models usually get wrong. Finally, `content-type` cannot be an attribute name, so it becomes `content_type` with the original key preserved in the field metadata; identifier-safe keys are left untouched, so a payload made entirely of them can still be constructed with `Root(**payload)`.
Key Capabilities & Features
🐍 Real Dataclasses, Not Dictionaries
`@dataclass` models with PEP 585 annotations for Python 3.9+, giving you a constructor, equality, `repr` and `asdict` out of the box.
🧩 Nested Classes & Shape Deduplication
Nested objects become named classes, and identical shapes collapse into one — a thousand-record array still generates a single class.
🕳️ Honest Nullability
Nulls and keys missing from some records become `Optional[X]` in the annotation only — never a default value that would reorder your constructor.
🔑 Original Keys Preserved
A key that cannot be an attribute name is folded to snake_case, with the exact wire name kept in the field metadata for your deserializer.
Where the Type Inference Stops Guessing
Inferring types from a single sample is a best-effort exercise, and it is far more useful to know exactly where it gives up than to pretend it never does.
- `int` versus `float`: JavaScript's `JSON.parse` cannot tell `1.0` from `1`, so a price that happened to be `19.0` in your sample is annotated `int`. Widen it by hand where a field is genuinely fractional.
- Fields that were only ever null: with no other evidence, the attribute is annotated `Any` rather than `Optional[Any]`, since `Any` already admits `None`.
- Heterogeneous arrays: every branch is kept, so `[1, "two"]` becomes `list[Union[int, str]]`. An empty array has nothing to infer from and becomes `list[Any]`. An array mixing objects with non-objects degrades to a union rather than merging into a class.
- Very large integers: values beyond 2^53 have already lost precision during parsing, before the generator ever sees them.
- Documents that are not objects: a top-level array of records generates the element class plus an alias — `Root = list[RootItem]` — so the document itself still has a name you can annotate against.
Treat the result as a very good first draft: exactly right for the sample you supplied, and worth a read-through before it lands in your codebase. If you need a runtime contract rather than static annotations, the JSON Schema generator infers one from the same payload, and if the same shape has to exist in your frontend too, the TypeScript interface generator produces the equivalent declarations from the identical inference pass.
The Sample You Paste Here Is Almost Always Real Production Data
Code generation makes the privacy question sharper than it is for a formatter, and for a structural reason: to get correct types you have to paste a real response. A hand-written toy example produces hand-written toy types, so what actually ends up in the input pane is typically copied straight out of a DevTools Network tab or a `curl` against staging. It carries real customer names, real email addresses, real internal identifiers — and, in the key names alone, a fairly complete map of your internal data model.
That payload never leaves this tab. Your JSON is parsed in a Web Worker inside your browser, and the classes are generated from the parsed value in the same page; no backend endpoint is involved in producing the output, there is no account to create, and there is no ad network sitting in the page alongside your data. Many free online generators do this work server-side instead, which makes the honest answer to "where did my payload go" something closer to "a machine you cannot inspect."
Rather than asking you to take that on trust, the entire project is open source: you or your security team can read the inference and emission code, fork it, or self-host it from the GitHub repository. And if the response you pasted turns out to be malformed before it can be typed at all, the JSON validator will point at the exact line and column that broke it.