# How to Use FastCRUD with Pydantic v2 Schemas: Complete Implementation Guide

> Master FastCRUD with Pydantic v2 schemas. This guide shows type-safe CRUD operations for SQLAlchemy models. Accelerate your development now.

- Repository: [Benav Labs/fastcrud](https://github.com/benavlabs/fastcrud)
- Tags: how-to-guide
- Published: 2026-02-26

---

**FastCRUD is built exclusively for Pydantic v2, leveraging the `model_dump()` API and generic type aliases bound to `BaseModel` to provide type-safe CRUD operations with SQLAlchemy models.**

FastCRUD is a modern Python library designed to accelerate FastAPI development by providing generic CRUD operations that integrate seamlessly with SQLAlchemy and Pydantic v2 schemas. Unlike legacy solutions that rely on Pydantic v1's `dict()` method, FastCRUD leverages the v2 `model_dump()` API for robust schema handling. This guide walks you through the architectural patterns, implementation files, and practical code examples needed to implement FastCRUD with Pydantic v2 schemas in your FastAPI applications.

## Architectural Overview of FastCRUD with Pydantic v2

FastCRUD's architecture centers on strict Pydantic v2 compliance. The library uses generic type parameters to ensure that all schema inputs and outputs conform to Pydantic v2's `BaseModel` interface.

### Core Type System and Generic Bindings

In [`fastcrud/types.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/types.py), FastCRUD defines generic type aliases that are explicitly bounded to Pydantic v2's `BaseModel`:

- **CreateSchemaType**: Used for `create()` operations
- **UpdateSchemaType**: Used for `update()` operations  
- **SelectSchemaType**: Used for `get()` and `get_multi()` return types
- **DeleteSchemaType**: Used for soft-delete configurations

These aliases ensure that any schema passed to FastCRUD methods inherits from `pydantic.BaseModel` and supports the v2 API.

### Schema Serialization Pipeline

When creating or updating records, FastCRUD converts Pydantic v2 schemas to dictionaries using the modern `model_dump()` method. In [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py), the `create()` method calls `object.model_dump()` (lines 106-108) to extract a plain Python dictionary that can be passed directly to the SQLAlchemy model constructor.

This approach replaces the deprecated Pydantic v1 `dict()` method and ensures compatibility with Pydantic v2's serialization behavior, including custom serializers and computed fields.

### Output Model Instantiation

FastCRUD supports returning Pydantic v2 models directly from database queries via the `return_as_model` parameter. When `return_as_model=True` and a `schema_to_select` is provided, FastCRUD instantiates the schema using the v2 constructor: `schema_to_select(**out)`.

This pattern appears in [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py) within the `get()` and `get_multi()` methods (around lines 100-105), allowing you to work with fully-typed Pydantic objects throughout your application layer.

## Implementing FastCRUD with Pydantic v2 Schemas in FastAPI

Integrating FastCRUD into a FastAPI application requires defining Pydantic v2 schemas that match your SQLAlchemy models, then wiring them into the generic `FastCRUD` class.

### Defining Pydantic v2 Schemas

Create schemas that inherit from `pydantic.BaseModel` and use Pydantic v2 configuration patterns. The [`fastcrud/examples/user/schemas.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/examples/user/schemas.py) file demonstrates the expected structure:

```python
from pydantic import BaseModel, ConfigDict
from datetime import datetime
from typing import Optional

class CreateUserSchema(BaseModel):
    name: str
    email: str
    is_active: bool = True

class ReadUserSchema(BaseModel):
    id: int
    name: str
    email: str
    created_at: datetime
    
    model_config = ConfigDict(from_attributes=True)

class UpdateUserSchema(BaseModel):
    name: Optional[str] = None
    email: Optional[str] = None

class DeleteUserSchema(BaseModel):
    pass

```

The `model_config = ConfigDict(from_attributes=True)` setting enables ORM mode, allowing Pydantic to read attributes from SQLAlchemy model instances when converting query results to schemas.

### Configuring the FastCRUD Instance

Instantiate `FastCRUD` with generic type parameters that map your SQLAlchemy model to its corresponding Pydantic v2 schemas:

```python
from fastcrud import FastCRUD
from fastcrud.examples.user.model import User  # SQLAlchemy model

from fastcrud.examples.user.schemas import (
    CreateUserSchema,
    ReadUserSchema,
    UpdateUserSchema,
    DeleteUserSchema,
)

# Generic signature: Model, CreateSchema, UpdateSchema, SelectSchema, DeleteSchema

UserCRUD = FastCRUD[User, CreateUserSchema, UpdateUserSchema, None, DeleteUserSchema]
user_crud = UserCRUD(User)

```

The `None` value for the fourth parameter indicates we will specify the select schema at call time rather than baking it into the instance.

### Auto-Generating CRUD Endpoints

Use `crud_router` from [`fastcrud/endpoint/crud_router.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/crud_router.py) to automatically create FastAPI routes that validate requests and responses using your Pydantic v2 schemas:

```python
from fastcrud import crud_router
from fastapi import FastAPI

router = crud_router(
    session=get_db,  # Your async session dependency

    model=User,
    create_schema=CreateUserSchema,
    read_schema=ReadUserSchema,      # Used for GET /users/{id}

    update_schema=UpdateUserSchema,
    delete_schema=DeleteUserSchema,
    path="/users",
    tags=["users"],
)

app = FastAPI()
app.include_router(router)

```

This router automatically handles the conversion between Pydantic v2 schemas and SQLAlchemy models using FastCRUD's internal `model_dump()` calls.

## Complete FastAPI Application Example

Below is a minimal, asynchronous FastAPI application demonstrating the full lifecycle of FastCRUD with Pydantic v2 schemas, including database setup and automatic endpoint generation.

```python

# app.py

import datetime
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker

from fastcrud import FastCRUD, crud_router
from fastcrud.examples.user.model import User  # SQLAlchemy model

from fastcrud.examples.user.schemas import (
    CreateUserSchema,
    ReadUserSchema,
    UpdateUserSchema,
    DeleteUserSchema,
)

# -------------------- Database setup --------------------

DATABASE_URL = "sqlite+aiosqlite:///./test.db"
engine = create_async_engine(DATABASE_URL, echo=True)
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)

async def get_db() -> AsyncSession:
    async with AsyncSessionLocal() as session:
        yield session

# -------------------- FastCRUD instance --------------------

UserCRUD = FastCRUD[User, CreateUserSchema, UpdateUserSchema, None, DeleteUserSchema]
user_crud = UserCRUD(User)

# -------------------- FastAPI router --------------------

router = crud_router(
    session=get_db,
    model=User,
    create_schema=CreateUserSchema,
    read_schema=ReadUserSchema,
    update_schema=UpdateUserSchema,
    delete_schema=DeleteUserSchema,
)

# -------------------- Application --------------------

app = FastAPI()
app.include_router(router, prefix="/users", tags=["users"])

```

This example demonstrates how FastCRUD handles the entire data flow: Pydantic v2 schemas validate incoming requests, `model_dump()` converts them to dictionaries for SQLAlchemy, and `return_as_model` instantiates schemas from database rows.

## Advanced Query Patterns with Pydantic v2 Schemas

FastCRUD extends beyond basic CRUD operations by supporting complex filtering, pagination, and relationship handling while maintaining Pydantic v2 compatibility.

### Filter Operators and Joined Models

FastCRUD automatically translates filter operators into SQLAlchemy expressions. You can use double-underscore notation to apply operators like `__contains`, `__eq`, `__gt`, and even traverse relationships:

```python

# Filter by substring

users = await user_crud.get_multi(
    db,
    email__contains="example.com",
    return_as_model=True,
    schema_to_select=ReadUserSchema,
)

# Filter across relationships (automatic JOIN handling)

items = await item_crud.get_multi(
    db,
    profile__company__name__eq="Acme",
    return_as_model=True,
    schema_to_select=ReadItemSchema,
)

```

This filtering logic is implemented in [`fastcrud/core/query/builder.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/query/builder.py), which parses the filter keys, validates the relationship paths, and constructs the necessary SQLAlchemy JOINs.

### Soft Delete Configurations

For applications requiring soft deletes, FastCRUD accepts a `DeleteSchemaType` that can include audit fields. Define a deletion schema and configure it in your CRUD instance:

```python
from pydantic import BaseModel
from datetime import datetime

class DeleteUserSchema(BaseModel):
    deleted_at: datetime
    is_deleted: bool = True

# Use in FastCRUD generic parameters

UserCRUD = FastCRUD[User, CreateUserSchema, UpdateUserSchema, None, DeleteUserSchema]

```

The deletion logic references [`fastcrud/core/config/crud_configs.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/config/crud_configs.py) for configuration structures, allowing you to inject timestamps or user IDs during soft-delete operations.

## Key Source Files for FastCRUD Pydantic v2 Integration

Understanding the source code helps when debugging schema conversion issues or extending functionality. These files contain the core Pydantic v2 integration points:

- **[`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py)** – Contains the generic `FastCRUD` class implementation. Look here for the `model_dump()` calls on lines 106-108 during create operations, and the `schema_to_select(**out)` instantiation pattern in `get()` and `get_multi()` methods around lines 100-105.

- **[`fastcrud/types.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/types.py)** – Defines the generic type aliases `CreateSchemaType`, `UpdateSchemaType`, `SelectSchemaType`, and `DeleteSchemaType` (lines 14-18), all explicitly bounded to Pydantic v2's `BaseModel`.

- **[`fastcrud/examples/user/schemas.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/examples/user/schemas.py)** – Reference implementation showing concrete Pydantic v2 schemas (`CreateUserSchema`, `ReadUserSchema`, `UpdateUserSchema`, `DeleteUserSchema`) with proper `ConfigDict` usage.

- **[`fastcrud/endpoint/crud_router.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/crud_router.py)** – Implements the `crud_router` function that automatically generates FastAPI endpoints from your Pydantic v2 schemas and FastCRUD instance.

- **[`fastcrud/core/query/builder.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/query/builder.py)** – Handles the parsing of filter operators (like `__contains`, `__eq`) and automatic JOIN construction for relationship filtering.

## Summary

FastCRUD provides a type-safe, generic CRUD layer built specifically for Pydantic v2 and SQLAlchemy. Key implementation points include:

- **Generic type binding**: `CreateSchemaType`, `UpdateSchemaType`, and related aliases in [`fastcrud/types.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/types.py) enforce Pydantic v2 `BaseModel` constraints at the type level.

- **Modern serialization**: The library uses `model_dump()` (not the deprecated `dict()`) to convert Pydantic v2 schemas to dictionaries before passing them to SQLAlchemy constructors, as seen in [`fastcrud/crud/fast_crud.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py).

- **Automatic endpoint generation**: The `crud_router` function in [`fastcrud/endpoint/crud_router.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/crud_router.py) consumes your Pydantic v2 schemas to generate fully-typed FastAPI endpoints with request validation and response serialization.

- **Advanced filtering**: Support for Pydantic v2 schemas in filter operations, including relationship traversal via double-underscore notation (`profile__company__name__eq`), implemented in [`fastcrud/core/query/builder.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/core/query/builder.py).

## Frequently Asked Questions

### Does FastCRUD support Pydantic v1?

No. FastCRUD is built exclusively for Pydantic v2. The library relies on the `model_dump()` method introduced in Pydantic v2 for schema serialization, and all generic type aliases in [`fastcrud/types.py`](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/types.py) are explicitly bounded to Pydantic v2's `BaseModel`. If you attempt to use Pydantic v1 schemas, you will encounter attribute errors when FastCRUD attempts to call `model_dump()`.

### How do I enable ORM mode for my Pydantic v2 schemas?

Add a `model_config` class attribute using `ConfigDict` with `from_attributes=True` to your schema definition. This allows Pydantic v2 to read attributes from SQLAlchemy model instances when FastCRUD converts database rows to schema instances via `schema_to_select(**out)`. For example:

```python
from pydantic import BaseModel, ConfigDict

class ReadUserSchema(BaseModel):
    id: int
    name: str
    
    model_config = ConfigDict(from_attributes=True)

```

### Can I use custom Pydantic v2 validators with FastCRUD?

Yes. FastCRUD passes your Pydantic v2 schemas directly to the SQLAlchemy model constructors after calling `model_dump()`, but validation occurs when you instantiate the schema itself. You can use Pydantic v2's `@field_validator` and `@model_validator` decorators in your `CreateSchemaType` or `UpdateSchemaType` classes, and FastCRUD will respect these validations because it receives already-validated schema instances from FastAPI's dependency injection system.

### What is the performance impact of using return_as_model?

When you set `return_as_model=True` and provide a `schema_to_select` parameter, FastCRUD instantiates Pydantic v2 models for every row returned by the database query. This adds a small serialization overhead compared to returning raw dictionaries, but provides full type safety and IDE autocomplete. For high-throughput endpoints where microseconds matter, set `return_as_model=False` and work with dictionaries, converting to Pydantic models only at the service layer when necessary.