mrkeyoor.com_
Sun 20 Sept 15:54 UTC
PyPIUtilsupdated 18 Sept 2026

dataclasses-json review

dataclasses-json 0.6.7 attaches JSON and dictionary conversion methods to standard Python dataclasses, either with `@dataclass_json` or `DataClassJsonMixin`. It understands nested dataclasses, abstract collections, UUIDs, decimals, datetimes, renamed keys, case conversion, and field-specific codecs. The ordinary `from_json()` and `from_dict()` routes construct objects without checking values against annotations. Validation is a separate Marshmallow schema call. The 0.6.7 release expanded abstract collection handling and added warnings when runtime type resolution is unreliable.

Verdict

dataclasses-json 0.6.7 installed in 0.2 seconds and used 2 MB in our sandbox, but its normal decoder accepts values that violate annotations. It is reasonable glue for existing dataclasses on Marshmallow 3; choose a validation-first model library for new untrusted inputs.

We installed it

Lab card: what happened when we installed dataclasses-jsonScreenshot of dataclasses-json documentation
Install✓ · 0.2s6 packages on disk · 2 MB
Importimport dataclasses_json in 0.31s · pure Python · py.typed · requires Python >=3.7,<4.0
Known vulns0(pip-audit)

Answers from our run

Does dataclasses-json install cleanly?

Yes. In a fresh container with an empty cache, pip install dataclasses-json finished in 0.2s, leaving 6 packages and 2 MB on disk. pip-audit reported no known vulnerabilities.

What does dataclasses-json need to run?

Python >=3.7,<4.0, and nothing compiled: it is pure Python. In our run import dataclasses_json succeeded in 0.31s, and the package ships py.typed for type checkers.

dataclasses-json or pydantic: which should you use?

pydantic: Choose it when the everyday parse path must validate untrusted values and emit JSON Schema. dataclasses-json 0.6.7 installed in 0.2 seconds and used 2 MB in our sandbox, but its normal decoder accepts values that violate annotations.

When should you not use dataclasses-json?

Every decode must validate annotations. The README shows from_json() accepting 42 for a str; only .schema().loads() raises ValidationError for that payload.

API stability4/5Across 0.6, the public vocabulary remains the decorator, mixin, four conversion methods, `config`, `LetterCase`, `Undefined`, and `CatchAll`. Release 0.6.7 extended collection support and type-resolution warnings inside that model. Confidence stops short of a top score because the package is still pre-1.0 and its direct decoder deliberately behaves differently from the generated Marshmallow schema.
Docs4/5The documentation demonstrates the required decorator order, mixin typing, nested objects, renamed keys, missing and unknown fields, custom codecs, schema validation, and the surprising datetime conversion. It even prints the wrong-type example that direct decoding accepts. The hosted site mirrors the README, leaving no deeper versioned reference when runtime annotation resolution or Marshmallow behavior needs diagnosis.
Maintenance2/5PyPI dates 0.6.7 to June 9, 2024. GitHub is unarchived and shows a push on May 5, 2026, but it also reports 165 open issues and pull requests. No released build has removed the Marshmallow `<4.0.0` ceiling. For users, repository movement without a new artifact does not deliver compatibility fixes, so maintenance scores below average.
Ecosystem3/5The registry data records 15,712,176 weekly downloads, and GitHub shows 1,486 stars. That is substantial use for a narrowly scoped bridge between standard dataclasses and Marshmallow 3. There is no broad plugin system or multi-format toolchain. Teams needing default validation, JSON Schema, attrs support, or more output formats will find larger surrounding ecosystems in Pydantic, cattrs, and mashumaro.

Use it if

  • Existing models are stdlib dataclasses and replacing them with a validation framework would create needless migration work.
  • The wire format uses camelCase or fixed external names that should be declared in dataclass metadata.
  • Each class needs an explicit policy to reject, discard, or retain unknown keys in a `CatchAll` field.
  • Only selected ingress points need Marshmallow validation; trusted internal conversions can use the shorter direct methods.
Skip it if

Setup reality

Our uncached Python 3.12 install of dataclasses-json 0.6.7 finished in 0.2 seconds, left 6 packages totaling 2 MB, and produced 0 pip-audit findings. The distribution is pure Python with 2 direct dependencies, declares Python >=3.7,<4.0, ships py.typed, and uses MIT. import dataclasses_json succeeded in 0.31 seconds.

Decorator order is fixed: put @dataclass_json above @dataclass. The mixin is easier for static analysis because its methods are visible in the base class. Marshmallow stays below version 4 through the package constraint. .schema() builds a schema object, so create it once for a hot path. Direct from_json() remains quicker to write but does not enforce annotated types.

Defaults fill absent keys. Avoid infer_missing unless assigning None to a non-Optional field is acceptable. Without an Undefined policy, from_dict() drops extra keys while the schema loader rejects them. Undefined.INCLUDE needs exactly one CatchAll member. Class-wide letter-case conversion also assumes the Python attributes begin in snake_case.

The built-in datetime path emits a number, applies the machine timezone to naive input, and returns an aware value. For ISO text, define encoder, decoder, and mm_field together so direct and schema conversions agree. Quote recursive forward references. Process-wide codec registrations affect every later class that sees that type, so install them during startup rather than per request.

Patterns

Decorate a dataclass for JSON conversion serialize-dataclass

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Person:
    name: str
    age: int = 0

person = Person(name='Ada', age=36)
payload = person.to_json()
copy = Person.from_json(payload)

`@dataclass_json` must be the outer decorator. In 0.6.7, `from_json()` constructs the object without enforcing its annotations.

Make serializer methods visible to type checkers support-static-analysis

from dataclasses import dataclass
from dataclasses_json import DataClassJsonMixin

@dataclass
class Person(DataClassJsonMixin):
    name: str

payload = Person('Ada').to_json()
result = Person.from_json(payload)

`DataClassJsonMixin` provides the same runtime methods while making them explicit in the class hierarchy for static analysis.

Convert class keys to camelCase convert-letter-case

from dataclasses import dataclass
from dataclasses_json import LetterCase, dataclass_json

@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Account:
    given_name: str
    account_id: int

text = Account('Ada', 7).to_json()
account = Account.from_json(text)

Class-level case conversion assumes the attributes already follow snake_case; other starting forms have undefined mappings.

Give one attribute a fixed wire key rename-field

from dataclasses import dataclass, field
from dataclasses_json import config, dataclass_json

@dataclass_json
@dataclass
class User:
    user_id: str = field(metadata=config(field_name='id'))

assert User('u-1').to_dict() == {'id': 'u-1'}

`field_name` handles a single contract-specific key. Use `LetterCase` only when the entire model follows one rule.

Leave an internal field out of JSON exclude-output-field

from dataclasses import dataclass, field
from dataclasses_json import Exclude, config, dataclass_json

@dataclass_json
@dataclass
class Session:
    user_id: str
    internal_note: str = field(
        default='',
        metadata=config(exclude=Exclude.ALWAYS),
    )

This exclusion affects output. A required excluded field prevents the class from reading its own JSON unless it has a default.

Decode an array with one cached schema decode-json-array

from dataclasses import dataclass
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Item:
    sku: str

item_schema = Item.schema()
items = item_schema.loads('[{"sku": "A1"}]', many=True)
text = item_schema.dumps(items, many=True)

Top-level arrays use Marshmallow's `many=True`. Build `Item.schema()` once instead of recreating it for every batch.

Reject a wrong field type at ingress validate-input

from dataclasses import dataclass
from dataclasses_json import dataclass_json
from marshmallow import ValidationError

@dataclass_json
@dataclass
class Person:
    name: str

try:
    person = Person.schema().loads('{"name": 42}')
except ValidationError as error:
    print(error.messages)

The direct decoder accepts this integer. Route untrusted payloads through `.schema().loads()` when a mismatch must fail.

Retain unknown keys in CatchAll handle-unknown-keys

from dataclasses import dataclass
from dataclasses_json import CatchAll, Undefined, dataclass_json

@dataclass_json(undefined=Undefined.INCLUDE)
@dataclass
class Event:
    kind: str
    extras: CatchAll

event = Event.from_dict({'kind': 'created', 'source': 'api'})

`Undefined.INCLUDE` requires one `CatchAll` member. Use `RAISE` for a closed schema or `EXCLUDE` when forwards-compatible additions should disappear.

Apply defaults to absent JSON keys apply-defaults

from dataclasses import dataclass, field
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Search:
    query: str
    tags: list[str] = field(default_factory=list)

search = Search.from_json('{"query": "paper"}')

A declared default preserves the type contract. `infer_missing` may insert `None` into a field that was never annotated Optional.

Make datetime JSON use ISO strings encode-iso-datetime

from dataclasses import dataclass, field
from datetime import datetime
from dataclasses_json import config, dataclass_json
from marshmallow import fields

@dataclass_json
@dataclass
class Event:
    created_at: datetime = field(metadata=config(
        encoder=datetime.isoformat,
        decoder=datetime.fromisoformat,
        mm_field=fields.DateTime(format='iso'),
    ))

All 3 hooks keep the direct and schema APIs consistent. Without them, a naive datetime becomes a timestamp and returns timezone-aware.

Attach a Decimal codec to one field add-custom-codec

from dataclasses import dataclass, field
from decimal import Decimal
from dataclasses_json import config, dataclass_json

@dataclass_json
@dataclass
class Price:
    amount: Decimal = field(metadata=config(
        encoder=str,
        decoder=Decimal,
    ))

price = Price.from_json('{"amount": "12.50"}')

These callables cover direct conversion. Add `mm_field` when the same class also loads data through its Marshmallow schema.

Decode a self-referential dataclass model-recursive-tree

from dataclasses import dataclass
from typing import Optional
from dataclasses_json import dataclass_json

@dataclass_json
@dataclass
class Node:
    value: str
    child: Optional['Node'] = None

root = Node.from_dict({'value': 'a', 'child': {'value': 'b'}})

Quote the recursive name. The project warns that blanket deferred annotations can confuse the runtime type lookup used by 0.6.7.

Alternatives

PackageRegistryPick it when
pydanticPyPIChoose it when the everyday parse path must validate untrusted values and emit JSON Schema.
marshmallowPyPIChoose it for explicit schema classes or a codebase that has already adopted Marshmallow 4.
mashumaroPyPIChoose it for generated dataclass serializers and formats beyond JSON.
cattrsPyPIChoose it when attrs and dataclass models must remain undecorated and one converter should own the rules.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.