Skip to content

Type Mappings and Custom Types

datamodel-code-generator allows you to customize how schema types are mapped to Python types. This is essential for projects with specific type requirements, datetime handling preferences, or third-party library integrations.

Quick Overview

Option Description
--type-mappings Map schema types to custom Python types
--strict-types Use Pydantic strict types for validation
--output-datetime-class Choose datetime output type
--use-pendulum Use Pendulum library for datetime types
--use-decimal-for-multiple-of Use Decimal for multipleOf constraints
format: "email" Email validation (requires email-validator)
format: "ulid" ULID type support (requires python-ulid)

--type-mappings

Maps schema type+format combinations to other format names. This allows you to override how specific formats are interpreted.

Format

--type-mappings <type+format>=<target_format> [<type+format>=<target_format> ...]

Basic Examples

# Map binary format to string (generates str instead of bytes)
datamodel-codegen --input schema.json --output models.py \
  --type-mappings "binary=string"

# Map email format to string (generates str instead of EmailStr)
datamodel-codegen --input schema.json --output models.py \
  --type-mappings "string+email=string"

# Multiple mappings
datamodel-codegen --input schema.json --output models.py \
  --type-mappings "string+email=string" "string+uuid=string"

Mapping Syntax

Syntax Description Example
format=target Map format (assumes string type) binary=string
type+format=target Map type with format string+email=string

Avoiding Pydantic Optional Extras

Some Pydantic types require optional dependencies. Use --type-mappings to generate plain types instead:

# Avoid pydantic[email] dependency (EmailStr requires email-validator)
--type-mappings "string+email=string" "string+idn-email=string"

# Generate str instead of UUID for uuid format
--type-mappings "string+uuid=string"

Available Target Formats

Target Generated Type
string str
integer int
number float
boolean bool
binary bytes
date datetime.date
date-time datetime.datetime
uuid UUID
email EmailStr
uri AnyUrl

pyproject.toml Configuration

[tool.datamodel-codegen]
type-mappings = [
    "string+email=string",
    "string+idn-email=string",
    "binary=string",
]

The minLength and maxLength of a format: binary string, written as bytes, count octets, as OpenAPI 3.1.1 specifies for unencoded binary data, so maxLength: 3 rejects "ééé", three characters in six octets.

msgspec decodes a JSON string into bytes as base64, so in msgspec.Struct output a format: binary field rejects "abc" and decodes "aGk=" into b"hi"; --type-mappings binary=string writes the field as str, which keeps the text as written.


--strict-types

Generates Pydantic strict types that don't perform type coercion during validation.

Available Strict Types

Value Strict Type Rejects
str StrictStr Integers, floats
int StrictInt Strings, floats
float StrictFloat Strings, integers
bool StrictBool Strings, integers
bytes StrictBytes Strings

A format: byte string stays Base64Str, or Base64Bytes with --type-mappings string+byte=binary, which decode base64 text, also with --strict-types str or bytes. With minLength or maxLength, such bytes are written as Annotated[bytes, Field(max_length=8), EncodedBytes(encoder=Base64Encoder)], which checks the lengths on the base64 text, as JSON Schema counts them, before decoding it. Pydantic checks them so from 2.10 on, and an explicit --target-pydantic-version 2 warns about each such field. Pydantic cannot check a pattern on the text of such bytes, so --field-constraints and --use-annotated leave it out with a warning.

Without --strict-types

class User(BaseModel):
    id: int  # Accepts "123" and converts to 123
    name: str  # Accepts 123 and converts to "123"
    active: bool  # Accepts 1 and converts to True

With --strict-types

datamodel-codegen --input schema.json --output models.py \
  --strict-types str int bool
from pydantic import StrictBool, StrictInt, StrictStr


class User(BaseModel):
    id: StrictInt  # Rejects "123", requires integer
    name: StrictStr  # Rejects 123, requires string
    active: StrictBool  # Rejects 1, requires boolean

When to use

  • API validation where type coercion is undesirable
  • Data pipelines requiring exact types
  • Security-sensitive applications
  • Testing environments requiring strict type checking

--output-datetime-class

Controls the Python type used for date-time formatted strings.

Value Output Type Description
datetime datetime.datetime Standard library datetime (default)
AwareDatetime pydantic.AwareDatetime Requires timezone info
NaiveDatetime pydantic.NaiveDatetime Rejects timezone info

Default behavior

from datetime import datetime


class Event(BaseModel):
    created_at: datetime  # Accepts both aware and naive
datamodel-codegen --input schema.json --output models.py \
  --output-datetime-class AwareDatetime
from pydantic import AwareDatetime


class Event(BaseModel):
    created_at: AwareDatetime  # Requires timezone, e.g., 2024-01-01T00:00:00Z

NaiveDatetime

datamodel-codegen --input schema.json --output models.py \
  --output-datetime-class NaiveDatetime
from pydantic import NaiveDatetime


class Event(BaseModel):
    created_at: NaiveDatetime  # Rejects timezone, e.g., 2024-01-01T00:00:00

When to use each

Use Case Recommended Class
REST APIs AwareDatetime
Database models datetime or NaiveDatetime
Logs with UTC timestamps AwareDatetime
Local time applications NaiveDatetime

--use-pendulum

Uses Pendulum library types instead of standard library datetime.

pip install pendulum
datamodel-codegen --input schema.json --output models.py --use-pendulum

Output

import pendulum


class Event(BaseModel):
    created_at: pendulum.DateTime
    date: pendulum.Date
    time: pendulum.Time

Benefits of Pendulum

  • Timezone handling is simpler and more intuitive
  • Human-friendly datetime manipulation
  • Better serialization defaults
  • Immutable by default

When to use

  • Projects already using Pendulum
  • Applications requiring complex datetime manipulation
  • When timezone handling is a priority

Email Format Support

The generator supports the email and idn-email string formats, which generate Pydantic's EmailStr type.

Required Dependency

The email format requires the email-validator package to be installed:

pip install email-validator
Or install Pydantic with the email extra:
pip install pydantic[email]

Schema Example

{
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "format": "email"
    }
  }
}

Output

from pydantic import BaseModel, EmailStr


class MyModel(BaseModel):
    email: EmailStr

Avoiding the Dependency

If you don't want to install email-validator, you can map email formats to plain strings:

datamodel-codegen --input schema.json --output models.py \
  --type-mappings "string+email=string" "string+idn-email=string"

This generates str instead of EmailStr.


ULID Format Support

The generator supports the ulid string format, which generates python-ulid types.

Required Dependency

The ulid format requires the python-ulid package to be installed:

pip install python-ulid
For Pydantic integration, use:
pip install python-ulid[pydantic]

Schema Example

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "ulid"
    }
  }
}

Output

from ulid import ULID
from pydantic import BaseModel


class MyModel(BaseModel):
    id: ULID

What is ULID?

ULID (Universally Unique Lexicographically Sortable Identifier) is an alternative to UUID that offers:

  • Lexicographic sorting - ULIDs sort naturally by creation time
  • Compactness - 26 characters vs 36 for UUID
  • URL-safe - Uses Crockford's Base32 encoding
  • Timestamp encoded - First 10 characters encode creation time

When to use

  • Distributed systems requiring time-ordered IDs
  • Applications where database index performance matters
  • When you need both uniqueness and sortability

--use-decimal-for-multiple-of

Uses Decimal type for numbers with multipleOf constraints to avoid floating-point precision issues.

The Problem

properties:
  price:
    type: number
    multipleOf: 0.01  # Currency precision

Without this option, floating-point arithmetic can cause validation issues:

# 0.1 + 0.2 = 0.30000000000000004 in floating-point
price = 0.30000000000000004  # May fail multipleOf validation

Solution

datamodel-codegen --input schema.json --output models.py \
  --use-decimal-for-multiple-of
from decimal import Decimal


class Product(BaseModel):
    price: Decimal  # Exact decimal arithmetic

When to use

  • Financial applications
  • Scientific calculations requiring precision
  • Any schema with multipleOf constraints

Forms and strict types

The default Pydantic output writes condecimal(...). With --field-constraints or --use-annotated the field is a float with its constraints in Field(). Add --use-decimal-in-field-forms (set by the 20261027 presets) to make it a Decimal with its constraints in Field() too, for example Annotated[Decimal, Field(ge=0, multiple_of=0.01)]. With that option, under --strict-types float the Decimal is strict: condecimal(..., strict=True), or strict=True among the Field() arguments. It rejects Python floats and, as Pydantic's strict Decimal does in JSON, accepts JSON numbers and numeric strings. A custom DataTypeManager receives every constraint of the schema in the field forms too, with field_constraints=True; the base class ignores them.


Common Patterns

Pattern 1: Minimal dependencies

Avoid optional Pydantic dependencies by mapping special formats to plain types:

datamodel-codegen --input schema.json --output models.py \
  --type-mappings "string+email=string" "string+idn-email=string"

Pattern 2: Strict API validation

datamodel-codegen --input schema.json --output models.py \
  --strict-types str int float bool \
  --output-datetime-class AwareDatetime \
  --field-constraints

Pattern 3: Financial application

datamodel-codegen --input schema.json --output models.py \
  --use-decimal-for-multiple-of \
  --strict-types str int

Pattern 4: Pendulum datetime handling

datamodel-codegen --input schema.json --output models.py \
  --use-pendulum \
  --strict-types str int

Type Mapping Reference

Common Format Mappings

Schema Format Default Type With --type-mappings "format=string"
email EmailStr str
idn-email EmailStr str
uuid UUID str
ulid ULID (requires python-ulid) str
uri AnyUrl str
binary bytes str

Other type customization options

For datetime types, use --output-datetime-class or --use-pendulum instead of --type-mappings.


See Also