Skip to main content
Real-world data is rarely flat. An order contains line items. A user has a billing address. An API response wraps a list of results in a metadata envelope. Pydantic handles all of this naturally — you use one model as the type annotation for a field inside another, and validation cascades through the entire structure automatically.

Using a model as a field type

To nest one model inside another, simply use the inner model’s class as the type annotation for a field:
You access nested fields with normal attribute chaining. Your IDE follows the types all the way down and provides autocompletion at every level.

Parsing nested data from a dictionary

The real power of nested models shows when you receive a nested dictionary — for example, from a JSON API response. You don’t need to construct inner models manually; Pydantic builds the entire object graph for you:
Pydantic sees that address should be an Address model, finds a dictionary at that key, and validates it automatically. If the nested dictionary is missing a required field or has a wrong type, you get a precise error pointing to the exact path that failed.

Lists of models

Use list[YourModel] to represent a collection of nested objects — a common pattern in API responses:
Output:
Each element in the items list is a fully validated OrderItem instance. If any item in the list has a bad value, Pydantic reports the exact index and field that failed.

Optional nested models

Mark a nested model as optional by using ModelName | None = None:
Pydantic accepts either a Discount instance or a plain dictionary for an optional nested field. Both are validated the same way — so you can pass raw API data without constructing objects manually.

Serializing nested models

When you call .model_dump() or .model_dump_json(), Pydantic recursively serializes all nested models too:
Output of model_dump_json:

Real-world example: Order with Customer and line items

Here is the kind of model hierarchy you’d encounter in a real e-commerce API. An Order contains a Customer (who has a billing Address), a list of OrderItem objects, and an optional Discount:
Output:
Notice that the created_at field is typed as datetime. Pydantic automatically parses the ISO 8601 string "2025-06-01T14:32:00Z" into a proper datetime object — no manual parsing required.

How nested models map to API schemas

This nesting pattern maps directly to how real API request and response bodies look. When you use FastAPI, you define your endpoint’s input type as a nested Pydantic model, and FastAPI:
  1. Reads the incoming JSON body
  2. Validates it against your model hierarchy
  3. Hands your endpoint function a fully typed, validated object
  4. Generates JSON Schema for the /docs page automatically
Your Pydantic model is your API schema. You define it once and get validation, documentation, and serialization for free.

Reusing models across your codebase

Defining small, focused models and composing them lets you avoid repetition:
Each model stays small and testable on its own, and you compose them into arbitrarily complex structures.

Ready to manage application configuration?

You now know how to model any hierarchical data structure — from a single nested object to a multi-level object graph with optional branches and lists. Next, learn how to load type-safe configuration for your application from environment variables and .env files.

Pydantic Settings

Read environment variables and .env files into a validated, type-safe Settings object.