JSON to Python Dataclass

Walks a JSON sample's shape and emits Python @dataclass definitions, bottom-up so nested classes are defined before use, with Optional[...] for nullable/optional fields and snake_case conversion for JSON keys that aren't valid Python identifiers. A free online tool from Staaarter, right in your browser.

Runs locallyUpdated 2026-07-26

Overview

Introduction

Writing Python dataclasses by hand for a JSON payload means tracking two easy-to-miss rules yourself: which fields need `Optional[...]` with a `None` default, and that every field with a default has to come after every field without one, or Python refuses to even define the class. This tool infers both directly from a real JSON sample.

It's one of four sibling generators on this site (TypeScript, Python, Go, Zod) that share the same shape-inference logic and differ only in how that shape is rendered as target-language code.

What Is JSON to Python Dataclass?

A generator that infers Python types from a JSON sample and emits `@dataclass`-decorated class definitions: `str`/`int`/`float`/`bool` for primitives, `list[T]` for arrays, and a separate nested `@dataclass` for every nested object, defined bottom-up so a class is always textually defined before anything that references it.

Fields observed as `null`, or missing from some elements of a merged array of objects, are typed `Optional[T] = None`. JSON keys that aren't valid Python identifiers (containing `-`, starting with a digit, etc.) are converted to snake_case, with a comment noting the original key so the mapping back to JSON stays visible.

The output is plain Python source text; nothing here executes Python or depends on a Python runtime, this tool only emits code you paste into your own project.

How JSON to Python Dataclass Works

The generator parses your JSON, then walks it via the same shared shape-inference step used by this site's TypeScript, Go, and Zod generators, classifying every value (string, integer, float, boolean, null, an array, or an object with named fields, tracking per-field nullability and, for arrays of objects, optionality).

Rendering that shape as Python hoists every object shape into its own `@dataclass`, inserted into the output only after all of its own nested classes have already been inserted, guaranteeing bottom-up ordering. Within each class, fields without a default (required, non-nullable) are listed before fields with a default (`Optional[...] = None`), which is required for the generated code to be syntactically valid Python.

The needed `from typing import Optional` (and `Any`, for a field whose value is always null or whose array elements are always empty) import line is added only when actually used, keeping the output free of unused imports.

When To Use JSON to Python Dataclass

Use it right after capturing a real API response or config sample, when you want typed Python classes for that shape (for autocomplete, static analysis with mypy/pyright, or documentation) without hand-transcribing every field.

It's also a fast way to get the field-ordering and Optional-typing rules right on the first try, both of which are easy to get subtly wrong by hand and only surface as a runtime SyntaxError when you actually try to use the class.

Features

Advantages

  • Automatically orders fields so required fields precede defaulted ones, avoiding Python's dataclass field-ordering SyntaxError.
  • Defines nested classes bottom-up, so the output is ready to paste as-is without manually reordering class definitions.
  • Converts non-identifier JSON keys to snake_case and annotates the original key inline, instead of silently producing invalid Python or dropping the field.
  • Shares its shape-inference behavior with this site's TypeScript, Go, and Zod generators, so field-level nullability/optionality decisions are consistent across all four output languages.

Limitations

  • Generates plain `dataclasses` definitions only, not a Pydantic model and not JSON (de)serialization code; parsing real JSON into these classes still needs a library like `dataclasses-json` or a hand-written `from_dict`, especially for renamed snake_case fields.
  • Renamed fields carry a comment with the original JSON key for humans to read, but dataclasses have no built-in mechanism to actually enforce or automate that key mapping at runtime.
  • Type inference is purely sample-based: a field that's always a string in your sample but sometimes a number in real data won't be reflected unless your sample shows both.
  • JSON's lack of an integer/float literal distinction (10 vs. 10.0 parse identically) means a field's inferred int vs. float type reflects only what your specific sample happened to contain.

Examples

Flat object

Input

{"id":1,"name":"Ada","active":true}

Output

from dataclasses import dataclass

@dataclass
class RootObject:
    id: int
    name: str
    active: bool

Each key gets its inferred Python type; no Optional import is needed since every field is required.

Nested object defined before the class that uses it

Input

{"address":{"city":"London"}}

Output

from dataclasses import dataclass

@dataclass
class RootObjectAddress:
    city: str

@dataclass
class RootObject:
    address: RootObjectAddress

RootObjectAddress is emitted first so it's already defined by the time RootObject references it.

Required field before an Optional one, and a renamed key

Input

[{"a":1,"user-id":2},{"a":3}]

Output

from dataclasses import dataclass
from typing import Optional

@dataclass
class RootObject:
    a: int
    user_id: Optional[int] = None  # JSON key: "user-id"

"a" (present in both elements) stays required and listed first; "user-id" (missing from the second element) becomes an annotated, renamed Optional field.

Best Practices & Notes

Best Practices

  • Generate from your most complete real sample; a field never present in your sample can't be inferred at all.
  • Check every field with a `# JSON key: "..."` comment for whether you need an actual parsing mapping (via dataclasses-json or a hand-written from_dict), not just the type hint.
  • Use the root name option to name the top-level class after the real entity it represents (Order, User) instead of leaving generated files all titled RootObject.
  • If your project already uses Pydantic, treat this output as a types reference to adapt rather than pasting it in unmodified, since Pydantic models have a different base and different validation behavior.

Developer Notes

Built on a shared shape-inference module (also used by this site's TypeScript, Go, and Zod generators). Field ordering within each class splits fields into `required` (not nullable, not optional) and `withDefault` (nullable or optional) and concatenates required-first, preserving each group's original relative order, since Python raises `SyntaxError: non-default argument follows default argument` otherwise. Bottom-up class ordering falls out naturally from when each class's declaration is inserted into an ordered Map: a nested object's declaration is only inserted after all of its own fields (including further-nested objects) have already been recursively rendered and inserted.

JSON to Python Dataclass Use Cases

  • Typing a REST API response or request payload for a Python client or backend.
  • Generating class skeletons for a config file read into Python at startup.
  • Producing type hints for mypy/pyright to check code that consumes a known JSON shape.
  • Documenting a JSON payload's shape in a form that's also directly usable Python code.

Common Mistakes

  • Pasting the output as-is and expecting `RootObject(**some_json_dict)` to work when keys were renamed to snake_case; the mapping back to the original JSON key needs an explicit step.
  • Manually reordering fields back to match the original JSON key order without realizing the generated order exists specifically to keep the class definition syntactically valid.
  • Assuming every Optional field is truly optional in the underlying API contract, rather than just absent from one specific sample element.

Tips

  • Pair with the JSON to Zod Schema or JSON Schema Generator tool when the same payload also needs runtime validation on the JavaScript/TypeScript side.
  • Search the output for `# JSON key:` comments to quickly find every field that will need explicit mapping if you add JSON parsing later.
  • If a class ends up with many Optional fields, consider whether your sample is representative or whether the API genuinely has that much variability.

References

Frequently Asked Questions