SQLAlchemy

SQLAlchemy is the most widely used Python library for working with relational databases. It has two main parts:
1. SQLAlchemy Core — a SQL expression language for writing database queries in Python.
2. SQLAlchemy ORM — maps Python classes to database tables so you can read and write rows as Python objects instead of raw SQL.

Unlike Django, which ships with its own ORM, FastAPI has no built-in database layer. SQLAlchemy is the common choice for FastAPI projects.
Supported databases: SQLite, PostgreSQL, MySQL, MariaDB, Oracle, and others.

Install


$ pip install sqlalchemy

# For PostgreSQL
$ pip install psycopg2-binary

# For MySQL
$ pip install pymysql
      

Terms

Engine

The Engine is the starting point — it manages the connection to the database. You create it once with a database URL and reuse it across the app.


from sqlalchemy import create_engine

# SQLite (file-based, good for development)
engine = create_engine("sqlite:///./app.db", echo=True)

# PostgreSQL
# engine = create_engine("postgresql://user:password@localhost/mydb")
      

Model

A Model is a Python class that represents a database table. Each class attribute maps to a column. SQLAlchemy ORM uses a declarative base class to register models.


from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column()
    email: Mapped[str] = mapped_column(unique=True)
      

Session

A Session is a workspace for database operations. You add, query, update, and delete objects through a session, then call commit() to save changes or rollback() to undo them.


from sqlalchemy.orm import Session

with Session(engine) as session:
    user = User(name="Amit", email="amit@example.com")
    session.add(user)
    session.commit()
      

How to Use (ORM Model)

Create Table

After defining models, create the tables in the database with Base.metadata.create_all().


from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column()
    email: Mapped[str] = mapped_column(unique=True)

engine = create_engine("sqlite:///./app.db")
Base.metadata.create_all(engine)   # Creates the users table
      

CRUD

Create, Read, Update, Delete — the four basic database operations:


from sqlalchemy.orm import Session
from sqlalchemy import select

with Session(engine) as session:
    # Create
    user = User(name="Amit", email="amit@example.com")
    session.add(user)
    session.commit()

    # Read
    users = session.scalars(select(User)).all()
    one_user = session.get(User, 1)          # by primary key

    # Update
    user = session.get(User, 1)
    user.name = "Amit Kumar"
    session.commit()

    # Delete
    session.delete(user)
    session.commit()
      

With FastAPI

In a FastAPI app, create the engine once and provide a database session per request using dependency injection:


from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

app = FastAPI()

def get_db():
    db = Session(engine)
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
def read_user(user_id: int, db: Session = Depends(get_db)):
    return db.get(User, user_id)

@app.post("/users/")
def create_user(name: str, email: str, db: Session = Depends(get_db)):
    user = User(name=name, email=email)
    db.add(user)
    db.commit()
    db.refresh(user)
    return user
      

Async SQLAlchemy

For async frameworks like FastAPI, SQLAlchemy provides async versions of the engine and session. Database I/O runs with await so other requests are not blocked while waiting for the database.
Install an async driver for your database:


# PostgreSQL
$ pip install asyncpg

# SQLite
$ pip install aiosqlite
      

create_async_engine()

create_async_engine() is the async equivalent of create_engine(). It creates an AsyncEngine that manages non-blocking connections to the database.
Use an async database URL (note the driver suffix +asyncpg or +aiosqlite):


from sqlalchemy.ext.asyncio import create_async_engine

# PostgreSQL (async)
engine = create_async_engine(
    "postgresql+asyncpg://user:password@localhost/mydb",
    echo=True,
)

# SQLite (async)
# engine = create_async_engine("sqlite+aiosqlite:///./app.db")
      

async_sessionmaker()

async_sessionmaker() is the async equivalent of sessionmaker(). It is a factory that produces AsyncSession objects — use it with async with and await for ORM operations:


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

engine = create_async_engine("postgresql+asyncpg://user:password@localhost/mydb")

AsyncSessionLocal = async_sessionmaker(
    engine,
    class_=AsyncSession,
    expire_on_commit=False,
)

async def get_users():
    async with AsyncSessionLocal() as session:
        result = await session.execute(select(User))
        return result.scalars().all()
      

Check Database Status

A common health-check pattern: open a connection, run a lightweight query (SELECT 1), and return True if the database responds or False if anything fails (network down, wrong credentials, database not running):


from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine

engine = create_async_engine("postgresql+asyncpg://user:password@localhost/mydb")

async def check_database() -> bool:
    try:
        async with engine.connect() as conn:
            await conn.execute(text("SELECT 1"))
        return True
    except Exception:
        return False

# Usage (e.g. FastAPI startup or /health endpoint)
# is_ok = await check_database()
      

How it works:
1. engine.connect() — opens an async connection from the pool.
2. text("SELECT 1") — runs a minimal query that every SQL database supports.
3. await conn.execute(...) — sends the query and waits for a response without blocking the event loop.
4. Returns False on any exception (connection refused, timeout, auth error, etc.).