Cheatsheet for pydantic.dataclasses vs BaseModel.
Basic
from pydantic.dataclasses import dataclass
@dataclass
class User:
id: int
name: str
User(id=1, name="Alice") # validates
Looks like stdlib @dataclass + Pydantic validation.
Config
from pydantic.dataclasses import dataclass
from pydantic import ConfigDict
@dataclass(config=ConfigDict(strict=True, extra="forbid"))
class User:
id: int
name: str
Defaults
@dataclass
class User:
id: int
name: str = "anonymous"
tags: list[str] = Field(default_factory=list)
Same defaults as BaseModel.
Validators
from pydantic import field_validator
@dataclass
class User:
age: int
@field_validator("age")
@classmethod
def positive(cls, v):
if v < 0: raise ValueError("non-negative")
return v
Works the same as BaseModel.
Validate at runtime
from pydantic import TypeAdapter
UserAdapter = TypeAdapter(User)
user = UserAdapter.validate_python({"id": 1, "name": "x"})
Or call constructor directly: User(id=1, name="x").
Convert from stdlib dataclass
from dataclasses import dataclass as std_dataclass
from pydantic import TypeAdapter
@std_dataclass
class StdUser:
id: int
name: str
# Validate stdlib dataclass via TypeAdapter
adapter = TypeAdapter(StdUser)
user = adapter.validate_python({"id": 1, "name": "x"})
Works for stdlib @dataclass (no Pydantic-specific behavior, just type checking).
attrs comparison
from attrs import define
@define
class User:
id: int
name: str
user = User(id=1, name="Alice") # no validation by default
attrs: no validation; configurable via converters / validators. Pydantic dataclass: validation by default.
When to use pydantic.dataclass
- You want stdlib
@dataclasssyntax + Pydantic validation. - Mixing with libraries that expect dataclasses.
When NOT:
- New code: BaseModel is the canonical Pydantic style.
- Need rich serialization features (
model_dump,model_dump_json, computed_field) — BaseModel.
Serialization
from dataclasses import asdict
user = User(id=1, name="x")
asdict(user) # works (stdlib)
# But Pydantic features not directly:
TypeAdapter(User).dump_python(user)
TypeAdapter(User).dump_json(user)
Mixed with BaseModel
@dataclass
class Address:
street: str
city: str
class User(BaseModel):
name: str
address: Address
Pydantic validates the Address via its dataclass schema.
Limitations
model_configisconfigarg here.model_validate→TypeAdapter(...).validate_python(...)or direct constructor.- Some BaseModel methods unavailable.
Performance
Same Rust core. Slightly less ergonomic API.
Common mistakes
- Expecting
model_dump()etc. on dataclass — use TypeAdapter or stdlibasdict. - Mixing pydantic.dataclass with BaseModel and getting confused validation behavior.
- Using pydantic.dataclass when BaseModel would do — adds friction.
Recommendation
Use BaseModel by default. Reach for pydantic.dataclass only when:
- An external API expects a stdlib-compatible dataclass.
- Migration path from stdlib
@dataclasscodebase.
Read this next
If you want my BaseModel-vs-dataclass comparison code, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .