Skip to content

📦 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.json containing {"title": "MyString", "type": "string"})
  • ❌ Type aliases cannot be combined with Annotated for Pydantic v1

📊 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)
Pydantic v1 TypeAlias TypeAlias
TypedDict type statement TypeAlias
dataclasses type statement TypeAlias
msgspec type statement TypeAlias

🤔 Why the difference?

  • Pydantic v2 requires TypeAliasType because it cannot properly handle TypeAlias annotations
  • Other output types (TypedDict, dataclasses, msgspec) use TypeAlias for better compatibility with libraries that may not expect TypeAliasType objects
  • Python 3.12+ uses the native type statement 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 v1

Generating RootModel

datamodel-codegen --input model.json --input-file-type jsonschema --output model.py

✨ Generated model.py (Pydantic v1)

# generated by datamodel-codegen:
#   filename:  model.json

from __future__ import annotations

from typing import Any, Optional, Union

from pydantic import BaseModel


class Model(BaseModel):
    __root__: Any


class UserId(BaseModel):
    __root__: str


class Status(BaseModel):
    __root__: Union[str, int]


class User(BaseModel):
    id: Optional[UserId] = None
    status: Optional[Status] = None

Generating TypeAlias annotation

datamodel-codegen --input model.json --input-file-type jsonschema --use-type-alias --output model.py

✨ Generated model.py (Python 3.10+)

# generated by datamodel-codegen:
#   filename:  model.json

from __future__ import annotations

from typing import Any, Optional, TypeAlias, Union

from pydantic import BaseModel

Model: TypeAlias = Any


UserId: TypeAlias = str


Status: TypeAlias = Union[str, int]


class User(BaseModel):
    id: Optional[UserId] = None
    status: Optional[Status] = None

🔸 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