TL;DR
- Define resources with
msgspec.Struct- Use
Schemaonly when you need migrations or validation
Schema & model types¶
AutoCRUD separates two concepts:
- Resource model – the Python type representing stored data
- Schema – the descriptor defining versioning, migrations, and validation
In most cases you will define your resource using msgspec.Struct.
Resource models (msgspec.Struct)¶
AutoCRUD primarily uses msgspec.Struct to define resource models.
These models define the payload stored in the resource system.
Why msgspec.Struct¶
1. Union types are ergonomic¶
msgspec provides strong support for union types, which are common when schemas evolve.
This makes it easy to represent variant payloads without complex validation logic.
2. High performance¶
msgspec is designed for fast serialization and deserialization, which is important for:
- high-throughput CRUD workloads
- large resource payloads
- heavy query operations
3. Partial decoding¶
msgspec allows efficient partial decoding, meaning only the required fields need to be decoded.
This helps reduce CPU and memory overhead in metadata-heavy workflows.
Other supported model types¶
AutoCRUD can also accept other model types.
Pydantic BaseModel¶
Pydantic models are supported and automatically converted to structs internally.
Behavior:
- AutoCRUD converts the model into a struct for storage
- the Pydantic model can be used as a validator
dataclass / TypedDict¶
These may work depending on configuration, but they are not the recommended primary schema type.
msgspec.Struct is the most predictable and performant option.
Schema (migration & validation)¶
AutoCRUD also provides the Schema descriptor, which defines:
- the target schema version
- migration steps
- optional validation logic
Example:
When AutoCRUD loads stored resources:
- it reads the stored version
- finds the shortest migration path
- executes migration steps automatically
See:
- How-to → Migrations
Practical guidance¶
Recommended workflow:
- Define your model using
msgspec.Struct - Register it with AutoCRUD
If schema evolution is needed:
# Legacy style (IO[bytes])
crud.add_model(
Schema(User, "v2").step("v1", migrate_v1_to_v2)
)
# Typed style (recommended) — source_type auto-decodes for you
def migrate_v1_to_v2(data: UserV1) -> UserV2:
return UserV2(name=data.name, age=data.age, role="user")
crud.add_model(
Schema(UserV2, "v2").step("v1", migrate_v1_to_v2, source_type=UserV1)
)
Summary¶
| Concept | Purpose |
|---|---|
msgspec.Struct |
defines the resource payload |
Schema |
defines versioning, migration, and validation |