Model or dataset
Fatal1ty/mashumaro avatar
Fatal1ty/mashumaro

mashumaro: dataclasses that serialize without a second model layer

High-performance serialization without replacing your data model

940 stars69 forksPythonApache-2.0

At a glance

What is it?
mashumaro reads the type annotations you already wrote and generates encoders and decoders for them, across dict, JSON, orjson, YAML, TOML, MessagePack and JSON Schema. It is a conversion library and says so plainly, which means validation and business rules stay where you put them.
Who is it for?
mashumaro suits teams that already keep their domain in dataclasses and want fast, typed conversion without adopting a second declarative model, and it is a poor fit if you are looking for request validation, a schema authority or an ORM, since the project states it does not try to be a validation framework or replace a model layer.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The model you already have becomes the serialization model

Most Python serialization libraries ask you to restate your data model in their own vocabulary. You write a Pydantic class, or a SQLAlchemy model, or a custom schema object, and then keep the dataclasses you use everywhere else in the business logic. mashumaro takes the opposite position. The README describes it as high performance serialization without replacing your data model, and the reason list opens with standard Python first: keep ordinary dataclasses, collections and type annotations, and add a lightweight mixin only when you want methods on a model.

That is a small promise with a large blast radius in a codebase. If a service already passes dataclasses between layers, or holds a Pydantic model only because the HTTP framework demanded it, then the model layer is duplicated today, and mashumaro's approach is to let one definition serve both.

The scope is deliberately narrow, and the documentation is explicit about it. Mashumaro focuses on typed data conversion and serialization, and it deliberately does not try to be a business rule validation framework or replace your model layer. Those two sentences matter more than any benchmark, because they tell you what you still have to build yourself: field constraints, cross field rules, and the policy for what a malformed request should do.

The audience is a Python service author who is tired of hand written to_dict and from_dict methods, and who wants the conversion code to follow the annotations automatically when the model changes.

A mixin on the class or a codec for the whole tree

The project offers two entry points, and picking the wrong one is the most common early mistake.

The first is the mixin. Add a mixin to a dataclass and the class gains methods for conversion, with the mixin chosen by the format you want: the packaging configuration names mashumaro.mixins.dict, mashumaro.mixins.msgpack and mashumaro.mixins.toml as separate modules, and the repository ships a stub file for the orjson variant at mixins/orjson.pyi. This is the ergonomic option, since the model is the thing that knows how to serialize itself.

The second is a codec, created as a reusable object for any supported root type, and the documentation gives the example of a codec for list[Event]. A codec is the option for a type you do not own. If the payload root is a built in collection, or a type from another package that you cannot add a mixin to, the codec is the only way in. The mypy configuration treats mashumaro.codecs.* as a module family, which matches that reading of the API surface.

Underneath both sits a core layer. The mypy overrides list mashumaro.core.meta.types.pack and mashumaro.core.meta.types.unpack as the pack and unpack entry points, and mashumaro.jsonschema.schema as the JSON Schema generator. The naming is telling: the library thinks in terms of packing a value into a representation and unpacking it back, and formats are layers over that core rather than separate implementations.

Code generated once instead of type inspection on every call

The performance claim in mashumaro is not about clever algorithms. It is about where the work happens. The README says mashumaro generates conversion code for the exact type shape instead of repeatedly inspecting it at runtime.

That distinction is the whole design. A reflective serializer walks the type hints on every call, resolves forward references, decides which encoder applies and then does it again for the next record. A generating serializer resolves the type shape once, at class definition time or at codec construction, and emits specialised functions. Repeated work becomes one time work, which is the kind of trade that matters in a hot path.

The consequence for a user is a start-up cost. Type resolution and code generation happen when the module is imported and the classes are defined, and the recursive and generic type support listed in the README means that resolution has real work to do. For a service that deserialises millions of records per hour, that is obviously worth it. For a CLI that converts one file and exits, the setup cost may exceed the saving.

The repository includes a benchmark directory with its own run script, and the README links to a benchmarks section, so comparative numbers exist somewhere in the project. They are not reproduced here, because a table measured on the maintainer's machine says less about your workload than the shape of your own data does.

Format support is an extra, not a dependency

The core package is small, and the packaging says why. The only mandatory runtime dependency is typing_extensions at 4.14.0 or newer, which is needed for the modern typing constructs the library works with.

Everything format specific is optional. The pyproject file declares four extras:

toml
[project.optional-dependencies]
orjson = ["orjson"]
msgpack = ["msgpack>=0.5.6"]
yaml = ["pyyaml>=3.13"]
toml = [
    "tomli-w>=1.0",
    "tomli>=1.1.0;python_version<'3.11'",
]

The toml extra is the one to read twice. Writing TOML needs tomli-w, and reading needs tomli on Python versions below 3.11, since the standard library gained tomllib in 3.11. The conditional dependency spelling python_version<'3.11' is how the package stops requiring a backport on interpreters that have it built in.

The base install therefore gives you dict and JSON style conversion, and anything else is an explicit choice at install time. That is a sensible design for a library that sits in many different environments, and it also means that an upgrade can quietly change which optional dependencies are present in a lockfile. The packaging config controls what is included in the distribution:

toml
[tool.setuptools.package-data]
mashumaro = [
    "py.typed",
    "mixins/orjson.pyi",
]

The py.typed marker is the important one. It tells type checkers that the package ships inline annotations, which is what makes the typed experience of the library hold up inside a strictly checked project.

Getting the project and its checks running

The repository is a normal Python package with a justfile for the routine tasks. The build target installs the development requirements and then installs the project itself in editable mode:

code
build:
    pip install -r requirements-dev.txt
    pip install -e .

So the first real use is not a pip install of a published wheel but an editable checkout, with the development requirements pulled in alongside it. The requirements file sits at the root of the repository, next to the justfile, the pyproject.toml and the benchmark directory.

The checks are separated from the build, which is the right arrangement for a library where typing regressions are the common failure. The lint target runs four tools over the package and its tests:

code
lint:
    ruff check mashumaro
    black --check mashumaro tests
    mypy mashumaro
    codespell mashumaro tests README.md .github/*.md

The mypy configuration in pyproject.toml is strict for a library: ignore_missing_imports is on, but disallow_untyped_defs and disallow_incomplete_defs are both enabled. A few module families get explicit exemptions, which reveals the shape of the implementation:

toml
[[tool.mypy.overrides]]
module = [
    'mashumaro.mixins.dict',
    'mashumaro.mixins.msgpack',
    'mashumaro.mixins.toml',
    'mashumaro.codecs.*',
]
disable_error_code = 'empty-body'

The empty-body exemption exists because mixin and codec definitions are declarations that gain their behaviour at runtime. The tests run with pytest, with a parallel variant using pytest tests -n auto, and a coverage variant using pytest --cov . tests. The default just target runs build and lint together, which tells you the maintainer treats a failed type check as a build failure.

What mashumaro will not do for you

The library's stated boundaries are the practical limits. It does not validate. There is no field constraint system, no coercion policy for bad input and no error taxonomy beyond what the generated code raises. If a payload arrives with a string where an integer is annotated, mashumaro will try to build the object and raise, and the handling of that exception is your code. That is a defensible division of labour, and it is also the reason the README insists it is not a business rule validation framework.

The second limit is model authority. mashumaro does not replace your model layer, so it will not give you a database schema, an OpenAPI document derived from your domain, or a migration story. The repository topics do include json-schema and openapi, and the package exposes a JSON Schema generator at mashumaro.jsonschema.schema, so schema output exists. What does not exist is any statement that this schema is the authority for your API contract.

The third limit is the Python floor. requires-python is set to >=3.10, and the classifiers list CPython 3.10 through 3.15. The project supports a wide interpreter range, which is good for adoption and means you will meet it in whatever environment it lands in.

Finally, the package is a single maintainer's project. The pyproject file lists one author, and the release history is steady but unhurried: v3.21 on 2026-05-07, v3.22 on 2026-05-26 and v3.23 on 2026-09-30. For a library whose value is a large generated surface, a single author is a dependency worth naming.

Against the standard library and against hand written converters

The realistic alternatives come in two shapes, and mashumaro sits between them.

The first is the standard library. json.dumps and json.loads will serialise a dataclass only after you convert it yourself, which is the from_dict and to_dict boilerplate that mashumaro exists to remove. For simple payloads, a plain dict is genuinely enough, and the standard library has no dependency, no code generation and no import cost. The difference in approach appears at the first nested generic or union: the standard library has no notion of the type, while mashumaro reads the annotation and produces the right structure.

The second is a validating framework, where a model class carries field rules and produces a schema. That approach gives you validation and a single source of truth for the contract, at the cost of introducing a model type and a second way to write your domain objects. mashumaro deliberately does not take that route, so choosing it means your validation lives somewhere else.

The third option, which nobody writes about, is generating the converters yourself from the same annotations using a code generator, for example a dataclass plugin for a template engine. The output is equivalent in kind, and you get full control, but the generator becomes a piece of infrastructure you maintain. mashumaro gives you that machinery as a dependency, with typing_extensions as its only required package.

The honest summary is that mashumaro optimises the conversion step and nothing around it.

Editorial conclusion

mashumaro suits teams that already keep their domain in dataclasses and want fast, typed conversion without adopting a second declarative model, and it is a poor fit if you are looking for request validation, a schema authority or an ORM, since the project states it does not try to be a validation framework or replace a model layer. Verify two things before adopting it: that your Python floor is 3.10, which is what requires-python declares, and that the extras you need are actually installed, because orjson, msgpack, yaml and toml are optional dependencies rather than bundled ones. If your payload is plain JSON with simple types, the standard library json module remains a reasonable choice, and the case for this library starts with nested generics, unions and Annotated types.

Frequently asked questions

What Python version does mashumaro require?

The pyproject.toml sets requires-python to >=3.10, and the classifiers list CPython 3.10 through 3.15. The only mandatory runtime dependency is typing_extensions at 4.14.0 or newer.

Does mashumaro do validation?

No, and the documentation says so directly: mashumaro focuses on typed data conversion and serialization and deliberately does not try to be a business rule validation framework or replace your model layer. Field rules and error handling stay in your code.

How do I add MessagePack or YAML support to mashumaro?

Both are optional extras. The pyproject.toml declares msgpack = ["msgpack>=0.5.6"] and yaml = ["pyyaml>=3.13"] under optional-dependencies, and the TOML extra pulls in tomli-w plus tomli on Python versions below 3.11.

What is the difference between the mashumaro mixin and a codec?

The mixin adds conversion methods to your own dataclass, while a codec is a reusable object created for any supported root type, such as list[Event], which matters when you do not own the root type. The mypy configuration lists mashumaro.mixins.dict, mashumaro.mixins.msgpack and mashumaro.mixins.toml alongside mashumaro.codecs.* as separate modules.

Can mashumaro generate a JSON Schema?

The packaging configuration lists mashumaro.jsonschema.schema as a module in the library, and the repository topics include json-schema and openapi. The mypy overrides for that module disable a return error check, which indicates the generator returns a schema object rather than annotating a return type.

Is mashumaro actively maintained?

The repository is not archived and the last push was on 2026-10-02, with release v3.23 published on 2026-09-30 after v3.22 on 2026-05-26 and v3.21 on 2026-05-07. The package metadata carries the Development Status classifier 5 - Production/Stable and lists a single author.

Official sources

  1. Fatal1ty/mashumaro on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fatal1ty-mashumaro.svg)](https://hysenlabs.com/projects/fatal1ty-mashumaro)

Was this useful?