Output Model Types¶
datamodel-code-generator supports multiple output model types. This page compares them to help you choose the right one for your project.
Quick Comparison¶
| Model Type | Validation | Serialization | Performance | Use Case |
|---|---|---|---|---|
| Pydantic v2 | Runtime | Built-in | Fast | New projects, APIs, data validation |
| Pydantic v2 dataclass | Runtime | Built-in | Fast | Pydantic validation with dataclass syntax |
| dataclasses | None | Manual | Fastest | Simple data containers, no validation needed |
| TypedDict | Static only | Dict-compatible | N/A | Type hints for dicts, JSON APIs |
| msgspec | Runtime | Built-in | Fastest | High-performance serialization |
Pydantic v2 (Recommended)¶
Use --output-model-type pydantic_v2.BaseModel
Pydantic v2 is recommended for new projects. It offers better performance and a modern API.
from pydantic import BaseModel, Field, RootModel
class Pet(BaseModel):
id: int = Field(..., ge=0)
name: str = Field(..., max_length=256)
tag: str | None = None
class Pets(RootModel[list[Pet]]):
root: list[Pet]
When to use¶
- New projects requiring data validation
- APIs requiring data validation
- Projects needing JSON Schema generation from models
Pydantic v2 dataclass¶
Use --output-model-type pydantic_v2.dataclass
Pydantic v2 dataclass combines the familiar dataclass syntax with Pydantic's validation capabilities.
from pydantic.dataclasses import dataclass
from typing import Optional
@dataclass
class Pet:
id: int
name: str
tag: Optional[str] = None
When to use¶
- Want to use dataclass syntax with Pydantic validation
- Migrating from dataclasses but need validation
- Prefer decorator-based class definition
dataclasses¶
Use --output-model-type dataclasses.dataclass
Python's built-in dataclasses for simple data containers without runtime validation.
from dataclasses import dataclass
from typing import Optional
@dataclass
class Pet:
id: int
name: str
tag: Optional[str] = None
Options for dataclasses¶
| Option | Description |
|---|---|
--frozen-dataclasses |
Generate immutable dataclasses (frozen=True) |
--keyword-only |
Require keyword arguments (kw_only=True, Python 3.10+) |
--dataclass-arguments |
Custom decorator arguments as JSON |
# Frozen, keyword-only dataclasses
datamodel-codegen --input schema.json --output-model-type dataclasses.dataclass \
--frozen-dataclasses --keyword-only --target-python-version 3.10
When to use¶
- Simple data structures without validation needs
- Performance-critical code where validation overhead matters
- Interoperability with code expecting dataclasses
TypedDict¶
Use --output-model-type typing.TypedDict
TypedDict provides static type checking for dictionary structures.
from typing import TypedDict, NotRequired
class Pet(TypedDict):
id: int
name: str
tag: NotRequired[str]
When to use¶
- Working with JSON APIs where data remains as dicts
- Static type checking without runtime overhead
- Gradual typing of existing dict-based code
Boundary payloads and partial updates¶
TypedDict is a good fit for data at an HTTP boundary. A PATCH payload can distinguish three cases:
- the key is missing, so the existing value should stay unchanged
- the key is present with
null, so the value should be cleared - the key is present with a value, so the value should be replaced
Use --strict-nullable when the difference between a missing key and a
nullable value matters:
datamodel-codegen --input user-patch.schema.json \
--output-model-type typing.TypedDict \
--strict-nullable \
--target-python-version 3.13 \
--output model.py
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UserPatch",
"type": "object",
"required": ["id"],
"properties": {
"id": {"type": "string", "readOnly": true},
"nickname": {"type": ["string", "null"]},
"bio": {"type": "string"}
},
"additionalProperties": false
}
from typing import NotRequired
from typing_extensions import TypedDict
class UserPatch(TypedDict, closed=True):
id: str
nickname: NotRequired[str | None]
bio: NotRequired[str]
Here nickname: NotRequired[str | None] means the key may be omitted, and
None is still a real value when the key is present. This follows
PEP 655, which added Required and
NotRequired for per-key presence in TypedDict.
If the schema marks response-only fields with readOnly, combine this with
--use-frozen-field to generate ReadOnly for TypedDict output:
datamodel-codegen --input user-patch.schema.json \
--output-model-type typing.TypedDict \
--strict-nullable \
--use-frozen-field \
--target-python-version 3.13 \
--output model.py
from typing import NotRequired, ReadOnly
from typing_extensions import TypedDict
class UserPatch(TypedDict, closed=True):
id: ReadOnly[str]
nickname: NotRequired[str | None]
bio: NotRequired[str]
ReadOnly comes from PEP 705. The
closed=True output comes from PEP 728
and represents additionalProperties: false for type checkers that understand
closed TypedDicts.
Background
The distinction between missing keys, None, and unset update arguments is
covered in Koudai Aono's PyCon US 2026 talk
Beyond Optional in Real-World Projects.
In datamodel-code-generator today, TypedDict and msgspec preserve that
boundary shape most directly. Pydantic models and dataclasses are usually a
better fit after the boundary has been normalized into application data.
msgspec¶
Use --output-model-type msgspec.Struct
msgspec offers high-performance serialization with validation.
pip install 'datamodel-code-generator[msgspec]'
datamodel-codegen --input schema.json --output-model-type msgspec.Struct --output model.py
from msgspec import Struct, field
from typing import Union, UnsetType
from msgspec import UNSET
class Pet(Struct):
id: int
name: str
tag: Union[str, UnsetType] = UNSET
When to use¶
- High-performance JSON/MessagePack serialization
- Memory-efficient data structures
- APIs with strict performance requirements
Choosing the Right Type¶
graph TD
A[Need runtime validation?] -->|Yes| B[Need best performance?]
A -->|No| C[Need type hints for dicts?]
B -->|Yes| D[msgspec.Struct]
B -->|No| G[Prefer dataclass syntax?]
G -->|Yes| H[pydantic_v2.dataclass]
G -->|No| I[pydantic_v2.BaseModel]
C -->|Yes| J[typing.TypedDict]
C -->|No| K[dataclasses.dataclass]
Decision Guide¶
- API with validation → Pydantic v2
- Validation with dataclass syntax → Pydantic v2 dataclass
- High-performance serialization → msgspec
- Simple data containers → dataclasses
- Dict-based JSON handling → TypedDict