Guide Home Part 1 - FastAPI Foundations Part 2 - Building Applications Part 3 - Pages and HTML Part 4 - Security and Deployment Part 5 - Going Further Capstone Build Plan Markdown Source All Guides

Chapter 12: Saving Data with SQLAlchemy and Alembic

EF Core is integrated into the .NET ecosystem. SQLAlchemy is powerful, mature, and more explicit. Alembic handles migrations.

SQLAlchemy 2.x declarative model:

from sqlalchemy import String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class Base(DeclarativeBase):
    pass


class Recipe(Base):
    __tablename__ = "recipes"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(120), nullable=False)
    instructions: Mapped[str] = mapped_column(Text, nullable=False)
    servings: Mapped[int] = mapped_column(nullable=False)

Repository-style function:

from sqlalchemy import select
from sqlalchemy.orm import Session


def get_recipe(session: Session, recipe_id: int) -> Recipe | None:
    return session.get(Recipe, recipe_id)


def list_recipes(session: Session) -> list[Recipe]:
    statement = select(Recipe).order_by(Recipe.title)
    return list(session.scalars(statement))

Important differences from EF Core:

For a newcomer, start with synchronous SQLAlchemy inside FastAPI unless you have a strong async database requirement. Sync database calls are commonly deployed behind multiple worker processes or threads. Async is powerful, but it adds constraints and does not automatically make database-bound apps faster.