📦 Root Models and Type Aliases¶
When a schema defines a simple type (not an object with properties), datamodel-code-generator creates a root model. If you don't want to introduce a new level of attribute access (.root) or want to use generated types as plain Python types in non-Pydantic code, you can use the --use-type-alias flag to generate type aliases instead of root models.
⚠️ Notes and Limitations¶
This functionality is experimental! Here are a few known issues:
- 📌 RootModel and type aliases do not fully support field-specific metadata (default, alias, etc). See Named Type Aliases for details.
- 🚫 Type aliases do not support some RootModel features (e.g.
model_config) - 📄 A RootModel or type alias is also generated for the main schema, allowing you to define a single type alias from a schema file (e.g.
model.jsoncontaining{"title": "MyString", "type": "string"}) - 🧩 Pydantic v2 type aliases express constraints as
Annotated[int, Field(ge=1)]instead ofconint(ge=1), because mypy and Pyright reject call expressions in type aliases. ADecimalmultipleOfusesannotated_types.MultipleOf, becauseFieldtypesmultiple_ofas a float. Validation, serialization, and JSON schema stay the same, except that on Pydantic 2.0.x a string alias withminLength: 0now keepsminLength: 0in its JSON schema. - 🔤 Pydantic v2 type aliases (
--use-type-aliasandpydantic_v2.dataclassoutput) cannot select Python's regex engine throughmodel_config, so patterns that need it, such as lookaround assertions, are generated as compiledre.compile(...)patterns. These aliases require Pydantic 2.8 or later in the environment that runs the generated code, because Pydantic 2.8 added support for compiled patterns. With--target-pydantic-version 2these patterns stay strings and every generated model that reaches the alias, directly or through other models, setsregex_engine="python-re", which works from Pydantic 2.5; hand-written models that embed generated ones must set it themselves, and an alias validated on its own then needsTypeAdapter(Alias, config=ConfigDict(regex_engine="python-re")). See Targeting a Pydantic version.
When --use-root-model-type-alias is enabled, roots with field constraints or
patterns that require Python regex configuration use a regular RootModel class
to preserve validation. Unconstrained roots and constraints already represented
in the alias type keep the alias form. This does not change --use-type-alias.
An existing custom pydantic_v2/RootModelTypeAlias.jinja2 remains selected;
that template is responsible for preserving its root constraints.
API scope parameters¶
Changed in 0.84.0
With --openapi-scopes api, OpenAPI path, query, header, and cookie parameter schemas that would be root models
are always generated as type aliases, exactly as --use-type-alias emits them, whatever the output model type
and options; 0.83.0 generated root models for them. Object parameters stay models, and component schemas keep
their usual root models. See
OpenAPI Options: Generate all API declarations.
API scope references¶
Changed in 0.84.0
With --openapi-scopes api, a $ref beside only annotations such as description, title, examples, or
x- extensions is the referenced model itself, so a parameter, body, or response that refers to a RootModel
component is that RootModel rather than a second one wrapping it. Siblings that change the values, or
nullable: true, still give a derived model. See
OpenAPI Options: Generate all API declarations.
📊 Type Alias Behavior by Output Type and Python Version¶
The type of type alias generated depends on the output model type and target Python version:
| Output Type | Python 3.12+ | Python 3.10-3.11 |
|---|---|---|
| Pydantic v2 | type statement |
TypeAliasType (typing_extensions) |
| TypedDict | type statement |
TypeAlias |
| dataclasses | type statement |
TypeAlias |
| msgspec | type statement |
TypeAlias |
Use --use-type-alias-type to force TypeAliasType for TypedDict,
dataclass, and msgspec output targeting Python 3.10 or 3.11. This option
implies --use-type-alias, so the two flags do not need to be combined.
Python 3.12 and newer still use the native type statement.
🤔 Why the difference?¶
- Pydantic v2 requires
TypeAliasTypebecause it cannot properly handleTypeAliasannotations - Other output types (TypedDict, dataclasses, msgspec) use
TypeAliasfor better compatibility with libraries that may not expectTypeAliasTypeobjects --use-type-alias-typeopts into runtimeTypeAliasTypeobjects for those output types on Python 3.10-3.11- Python 3.12+ uses the native
typestatement for all output types
📝 Example¶
model.json¶
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"UserId": {
"type": "string"
},
"Status": {
"anyOf": [
{"type": "string"},
{"type": "integer"}
]
},
"User": {
"type": "object",
"properties": {
"id": {"$ref": "#/definitions/UserId"},
"status": {"$ref": "#/definitions/Status"}
}
}
}
}
🔸 Pydantic v2¶
Generating RootModel¶
datamodel-codegen --input model.json --input-file-type jsonschema --output-model-type pydantic_v2.BaseModel --output model.py
✨ Generated model.py (Pydantic v2)¶
# generated by datamodel-codegen:
# filename: model.json
from __future__ import annotations
from typing import Any, Optional, Union
from pydantic import BaseModel, RootModel
class Model(RootModel[Any]):
root: Any
class UserId(RootModel[str]):
root: str
class Status(RootModel[Union[str, int]]):
root: Union[str, int]
class User(BaseModel):
id: Optional[UserId] = None
status: Optional[Status] = None
Generating type statement (Python 3.12+)¶
datamodel-codegen --input model.json --input-file-type jsonschema --output-model-type pydantic_v2.BaseModel --use-type-alias --target-python-version 3.12 --output model.py
✨ Generated model.py (Python 3.12+ type statement)¶
# generated by datamodel-codegen:
# filename: model.json
from __future__ import annotations
from typing import Any, Optional, Union
from pydantic import BaseModel
type Model = Any
type UserId = str
type Status = Union[str, int]
class User(BaseModel):
id: Optional[UserId] = None
status: Optional[Status] = None
📖 See Also¶
- 🖥️ CLI Reference:
--use-type-alias- Detailed CLI option documentation - 🖥️ CLI Reference:
--use-type-alias-type- Force runtime type alias objects before Python 3.12 - 🎯 CLI Reference:
--target-python-version- Control Python version-specific syntax