Configuration on Pydantic models via model_config
Pydantic models support configuration through the model_config class attribute, which accepts a ConfigDict. A plain dictionary can also be used instead of ConfigDict. Example: class Model(BaseModel): model_config = ConfigDict(str_max_length=5); v: str
Configuration on Pydantic models via class arguments
Pydantic models can also be configured using class arguments, such as frozen=True. Unlike model_config, class arguments are recognized by static type checkers. For frozen, any instance mutation will be flagged as a type checking error.
Inheritance of model configuration
Configuration is inherited by subclasses from parent BaseModel classes. When a subclass provides its own configuration, it is merged with the parent configuration rather than replacing it.
Configuration inheritance with multiple bases
If a model inherits from multiple bases, Pydantic currently does not follow Python's Method Resolution Order (MRO) for configuration inheritance. See GitHub issue #9992 for details.
plugin_settings configuration
The plugin_settings configuration value passes options to Pydantic plugins as a dictionary keyed by plugin name. Each plugin reads only its own entry. The main plugin in use is Logfire for observability, which can record validations per model.
Config class deprecated in Pydantic V2
In Pydantic V1, the Config class was used for configuration. In Pydantic V2, the Config class is still supported but deprecated in favor of model_config.
Forward annotations with future import
Forward annotations are supported in Pydantic using either PEP 563's `from __future__ import annotations` statement or by wrapping type hints in string quotes. With the future import, all annotations are automatically treated as strings and resolved at model creation time, allowing types like MyInt to work without prior definition.
Self-referencing recursive models
Pydantic supports self-referencing models where a field references its own class. The annotation can be wrapped in a string like 'Foo | None' or the `from __future__ import annotations` import can be used. Annotations are resolved during model creation, allowing recursive structures like linked lists or tree nodes.
Cyclic reference detection during validation
When validating data with cyclic references, Pydantic detects the cycle and raises a ValidationError with type 'recursion_loop' instead of allowing a RecursionError. This happens before maximum recursion depth is exceeded, making it safe to catch and handle the ValidationError without concerns about limited remaining recursion depth.
Handling cyclic references in validation with field validators
A field_validator with mode='wrap' can catch ValidationError for cyclic references and selectively filter out the problematic cyclic data. By checking if the error type is 'recursion_loop' and iterating through individual children while suppressing recursion errors, you can validate nested structures while excluding cyclic branches.
Circular reference detection during serialization
During serialization, Pydantic raises a ValueError immediately when a circular reference is detected rather than waiting for maximum recursion depth to be exceeded. The error message format is 'Circular reference detected (id repeated)'.
Handling circular references in serialization with field serializer
A field_serializer with mode='wrap' can catch ValueError for circular references and selectively serialize nodes, excluding children when a circular reference would occur. By catching ValueError with message starting with 'Circular reference' and serializing node references instead of full nodes, circular graphs can be safely serialized.
Extra data handling default behavior
By default, Pydantic models ignore extra data provided during initialization. Extra data is not stored or included in model_dump() output.
Extra configuration values: ignore, forbid, allow
The 'extra' configuration value controls extra data behavior: 'ignore' (default) ignores extra data, 'forbid' raises an error when extra data is provided, 'allow' stores extra data in the __pydantic_extra__ dictionary attribute. The __pydantic_extra__ can be explicitly annotated to provide validation for extra fields. Validation methods have an optional 'extra' argument that overrides the model's config value.
model_construct() with extra data behavior
For models with extra='allow', extra data is correctly stored in __pydantic_extra__. For extra='ignore', extra data is ignored and not stored. For extra='forbid', a call to model_construct() does not raise an error with extra data, unlike normal instantiation - the extra data is simply ignored.
from_attributes configuration for ORM mode
The from_attributes configuration value (formerly 'ORM mode') enables validation of arbitrary objects by getting attributes corresponding to field names. Enable with ConfigDict(from_attributes=True) or using the from_attributes parameter on model_validate(). Useful for integrating with object-relational mappings (ORMs) like SQLAlchemy.
Nested attributes in from_attributes mode
When using from_attributes to validate models, model instances are created from both top-level attributes and deeper-nested attributes as appropriate. Nested objects are automatically converted to model instances if they match nested model field types.
Frozen models for immutability
Models can be configured immutable via model_config['frozen'] = True. Attempting to change instance attribute values raises ValidationError. However, Python immutability is not enforced - developers can still modify objects if they choose.
Frozen model pitfall with mutable attributes
When a frozen model contains mutable attributes like dicts or lists, the immutability only prevents reassignment of the attribute itself. The mutable object itself can still be modified (e.g., foobar.b['key'] = 'value' works even when foobar.b = newdict fails).
revalidate_instances configuration for attribute copies
By default, when model instances are passed during validation, they are used as-is without revalidation. Set model_config['revalidate_instances'] = 'always' to force revalidation and copying of model instances.
validate_call custom configuration with ConfigDict
The config parameter of validate_call can be used to specify custom configuration using ConfigDict, similar to Pydantic models. For example, config=ConfigDict(arbitrary_types_allowed=True) allows arbitrary custom types to be validated.
validate_call example with custom configuration
Example using ConfigDict with arbitrary_types_allowed:
from pydantic import ConfigDict, validate_call
class Foobar:
def __init__(self, v: str):
self.v = v
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
def add_foobars(a: Foobar, b: Foobar):
return a + b
This allows custom type Foobar to be validated in function arguments.