How to Use FastCRUD with Existing FastAPI Applications: A Complete Integration Guide

FastCRUD integrates with existing FastAPI applications by generating async CRUD endpoints through the crud_router function, which creates an APIRouter that can be directly included in your main FastAPI app using standard include_router patterns.

The benavlabs/fastcrud library provides a thin abstraction layer that adds async-ready, feature-rich CRUD operations on top of SQLAlchemy 2.x (or SQLModel) models. By leveraging the crud_router builder and EndpointCreator classes, you can wire fully functional REST endpoints into existing FastAPI projects without refactoring your database layer or application structure.

Understanding FastCRUD's Architecture

FastCRUD operates through three distinct layers that work together to generate endpoints while preserving your existing FastAPI setup.

The Core CRUD Layer

The FastCRUD class in [fastcrud/crud/fast_crud.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py) provides generic methods including create, get, get_multi, get_joined, update, delete, db_delete, upsert, and count. This class handles advanced filtering, sorting, cursor-pagination, and multi-dialect upserts while remaining completely model-agnostic.

The Router Builder

The [fastcrud/endpoint/crud_router.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/crud_router.py#L19-L84) file contains the crud_router convenience function (lines 19-84). This function instantiates EndpointCreator and returns a fully configured APIRouter that you can immediately include in your existing FastAPI application using app.include_router().

The Endpoint Creator

The [fastcrud/endpoint/endpoint_creator.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/endpoint_creator.py#L62-L140) class implements the actual endpoint functions (_create_item, _read_item, _read_items, etc.) on lines 62-140. It handles dependency injection, automatic relationship inclusion, filter validation, and response-model conversion before registering routes with the router.

Step-by-Step Integration Guide

Integrating FastCRUD into an existing FastAPI application requires four main steps: defining schemas, creating a session dependency, generating the router, and including it in your app.

Define Your SQLAlchemy Models and Pydantic Schemas

FastCRUD requires SQLAlchemy 2.x declarative models (or SQLModel) and separate Pydantic schemas for create, update, and read operations.


# app/models.py

from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

class Item(Base):
    __tablename__ = "items"
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    description = Column(String)

# app/schemas.py

from pydantic import BaseModel

class ItemCreateSchema(BaseModel):
    name: str
    description: str | None = None

class ItemReadSchema(BaseModel):
    id: int
    name: str
    description: str | None = None

Create an Async Session Dependency

FastCRUD expects a callable that returns an AsyncSession, typically wrapped in FastAPI's Depends.


# app/database.py

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from typing import AsyncGenerator

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

async def get_session() -> AsyncGenerator[AsyncSession, None]:
    async with AsyncSessionLocal() as session:
        yield session

Generate the CRUD Router

Use the crud_router function to create an APIRouter instance configured for your model.


# app/main.py

from fastapi import FastAPI
from fastcrud import crud_router
from .database import get_session, engine
from .models import Base, Item
from .schemas import ItemCreateSchema, ItemReadSchema

app = FastAPI()

@app.on_event("startup")
async def init_db():
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

item_router = crud_router(
    session=get_session,
    model=Item,
    create_schema=ItemCreateSchema,
    update_schema=ItemCreateSchema,
    select_schema=ItemReadSchema,
    path="/items",
    tags=["Items"],
)

app.include_router(item_router)

The crud_router function (lines 19-84 in fastcrud/endpoint/crud_router.py) instantiates EndpointCreator and returns a router that implements POST /, GET /{pk}, GET /, PATCH /{pk}, and DELETE /{pk} endpoints.

Advanced Integration Patterns

Once basic integration is working, you can customize the generated endpoints to fit your existing application's requirements.

Adding Authentication Dependencies

Inject custom dependencies into specific CRUD operations using the read_deps, create_deps, update_deps, and delete_deps parameters.

from fastapi import Depends, HTTPException, status
from .deps import get_current_user

item_router = crud_router(
    session=get_session,
    model=Item,
    create_schema=ItemCreateSchema,
    update_schema=ItemCreateSchema,
    select_schema=ItemReadSchema,
    path="/items",
    tags=["Items"],
    read_deps=[get_current_user],
    update_deps=[get_current_user],
    delete_deps=[get_current_user],
)

The EndpointCreator.add_routes_to_router method (lines 77-84 in fastcrud/endpoint/endpoint_creator.py) receives these dependency lists and passes them to FastAPI's router.add_api_route via the inject_dependencies utility.

Enabling Automatic Relationship Joins

FastCRUD can automatically detect and join SQLAlchemy relationships, returning nested data structures in your API responses.


# models.py

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship

class Category(Base):
    __tablename__ = "categories"
    id = Column(Integer, primary_key=True)
    name = Column(String)

class Item(Base):
    __tablename__ = "items"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    category_id = Column(Integer, ForeignKey("categories.id"))
    category = relationship("Category", backref="items")

# schemas.py

class CategoryReadSchema(BaseModel):
    id: int
    name: str

class ItemReadSchema(BaseModel):
    id: int
    name: str
    category: CategoryReadSchema | None = None

# main.py

item_router = crud_router(
    session=get_session,
    model=Item,
    create_schema=ItemCreateSchema,
    update_schema=ItemCreateSchema,
    select_schema=ItemReadSchema,
    path="/items",
    tags=["Items"],
    include_relationships=True,
    nest_joins=True,
)

The join configuration logic resides in EndpointCreator._get_join_params (lines 61-84 in fastcrud/endpoint/endpoint_creator.py), which builds the parameters for FastCRUD.get_multi_joined and get_joined calls.

Custom Endpoints with EndpointCreator

For complex business logic that extends beyond standard CRUD, use EndpointCreator directly to mix auto-generated and custom routes.

from fastcrud import EndpointCreator
from fastapi import APIRouter, Depends
from sqlalchemy import select, func

custom_creator = EndpointCreator(
    session=get_session,
    model=Item,
    create_schema=ItemCreateSchema,
    update_schema=ItemCreateSchema,
    select_schema=ItemReadSchema,
)

async def price_summary(
    category_id: int | None = None,
    db: AsyncSession = Depends(get_session),
):
    query = select(func.sum(Item.price))
    if category_id is not None:
        query = query.where(Item.category_id == category_id)
    result = await db.execute(query)
    total = result.scalar_one_or_none() or 0
    return {"total_price": float(total)}

# Add standard CRUD routes

custom_creator.add_routes_to_router()

# Add custom business logic endpoint

custom_creator.add_custom_route(
    endpoint=price_summary,
    methods=["GET"],
    path="/price-summary",
    tags=["Analytics"],
    summary="Total price of items (optional filter by category)",
)

app.include_router(custom_creator.router, prefix="/items")

The add_custom_route method (lines 71-84 in fastcrud/endpoint/endpoint_creator.py) forwards to FastAPI's router.add_api_route, allowing seamless integration of custom handlers alongside library-generated endpoints.

Summary

  • FastCRUD provides a model-agnostic CRUD layer in fastcrud/crud/fast_crud.py with async operations, advanced filtering, and relationship joining.
  • The crud_router function in fastcrud/endpoint/crud_router.py generates a complete APIRouter that plugs into existing FastAPI applications via app.include_router().
  • EndpointCreator in fastcrud/endpoint/endpoint_creator.py handles endpoint implementation, dependency injection, and custom route registration.
  • Integration requires only four steps: define schemas, create an async session dependency, call crud_router, and include the resulting router.
  • Advanced features include per-endpoint authentication dependencies, automatic SQLAlchemy relationship joining, and custom endpoint mixing through direct EndpointCreator usage.

Frequently Asked Questions

Can I use FastCRUD with an existing SQLAlchemy database setup?

Yes. FastCRUD is designed to work with existing SQLAlchemy 2.x declarative models and database engines. You do not need to modify your table definitions or migration scripts. Simply pass your existing model class to the crud_router function along with your current async session dependency, and FastCRUD will inspect the model metadata to generate appropriate endpoints.

How do I add authentication to specific CRUD endpoints?

Use the dependency injection parameters in crud_router or EndpointCreator. Pass a list of dependency callables to read_deps, create_deps, update_deps, or delete_deps to secure specific operations. These dependencies are forwarded to FastAPI's router.add_api_route via the inject_dependencies utility in EndpointCreator.add_routes_to_router (lines 77-84), ensuring standard FastAPI dependency resolution.

Yes. Set include_relationships=True when calling crud_router to enable automatic detection of SQLAlchemy relationships. Use nest_joins=True to return nested JSON structures rather than flat column results. The join configuration logic resides in EndpointCreator._get_join_params (lines 61-84), which builds parameters for FastCRUD.get_multi_joined and get_joined methods to handle the actual database queries.

Can I mix auto-generated CRUD routes with custom business logic endpoints?

Absolutely. Instantiate EndpointCreator directly instead of using the crud_router convenience function. Call add_routes_to_router() to register standard CRUD endpoints, then use add_custom_route() (lines 71-84 in endpoint_creator.py) to register bespoke endpoints that mix CRUD operations with custom business logic. Finally, include the EndpointCreator.router in your FastAPI app using app.include_router().

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →