Pydantic v2 performance best practices. Use when writing or reviewing Pydantic models, TypeAdapters, validators, or union types. Avoids common pitfalls that silently degrade validation throughput.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Pydantic v2 performance best practices. Use when writing or reviewing Pydantic models, TypeAdapters, validators, or union types. Avoids common pitfalls that silently degrade validation throughput.
Pydantic Best Practices
Official Pydantic performance skill. Apply when writing new models or reviewing existing ones.
Prefer model_validate_json() over model_validate(json.loads(...))
model_validate(json.loads(...)) parses JSON in Python, converts to a dict, then validates. model_validate_json() validates directly from the raw JSON string inside Rust - skip the intermediate dict entirely.
import json
from pydantic import BaseModel
classUser(BaseModel):
id: int
name: str
raw = '{"id": 1, "name": "Alice"}'# DO NOT DO THIS
user = User.model_validate(json.loads(raw))
# Do this
user = User.model_validate_json(raw)
Exception: when using a 'before' or 'wrap' validator on the model, the two-step method can be faster. Benchmark before assuming.
Instantiate TypeAdapter once, not per call
Every TypeAdapter(...) call builds a new validator and serializer. Move it to module level or a class attribute.
Use concrete types instead of abstract collections
Sequence forces an isinstance check and tries multiple concrete types. Mapping does the same. Use list, tuple, or dict when you know the exact type.
from collections.abc import Mapping, Sequencefrom pydantic import BaseModel
# DO NOT DO THISclassSlowModel(BaseModel):
items: Sequence[int]
meta: Mapping[str, str]
# Do thisclassFastModel(BaseModel):
items: list[int]
meta: dict[str, str]
Use Any when validation is not needed
Pydantic skips all validation for Any fields. Use it when the value is already trusted or will be validated elsewhere.
from typing importAnyfrom pydantic import BaseModel
classEvent(BaseModel):
name: str
payload: Any# raw blob, no validation cost
Avoid subclassing primitives for extra attributes
Pydantic must inspect subclasses of primitives specially. Carry extra state in a model field instead.
from pydantic import BaseModel
# DO NOT DO THISclassCompletedStr(str):
def__init__(self, s: str):
self.s = s
self.done = False# Do thisclassTask(BaseModel):
value: str
done: bool = False
Use discriminated (tagged) unions over plain unions
Plain unions try each branch in order. A discriminated union resolves the type in O(1) via a Literal discriminator field.
Use TypedDict over nested models for inner structures
TypedDict has lower overhead than a full BaseModel when the inner structure doesn't need methods, validators, or serialization customisation.
from typing import TypedDict
from pydantic import BaseModel
# Prefer this for nested, plain data shapesclassAddress(TypedDict):
street: str
city: str
zip_code: strclassUser(BaseModel):
name: str
address: Address
Avoid wrap validators on hot paths
Wrap validators materialise data as Python objects during validation, bypassing the Rust-side fast path. Prefer before, after, or field_validator modes.
from pydantic import BaseModel, field_validator
# Avoid on hot paths# @model_validator(mode='wrap')# def validate_model(cls, value, handler): ...# PreferclassOrder(BaseModel):
amount: float @field_validator('amount') @classmethoddefmust_be_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError('amount must be positive')
return v
Use FailFast on sequences to short-circuit on first error
Available from Pydantic v2.8+. Trades full error visibility for reduced work when early rejection is acceptable.
from typing import Annotated
from pydantic import FailFast, TypeAdapter, ValidationError
_bool_list_adapter = TypeAdapter(Annotated[list[bool], FailFast()])
try:
_bool_list_adapter.validate_python([True, 'invalid', False, 'also invalid'])
except ValidationError as exc:
# Only the first error is reported - stops after 'invalid'print(exc)
Do not apply FailFast when you need to surface all validation errors to an end user.