September 22, 2026
2 min read
Modern database toolkit for Python. Two layers: Core (SQL expression language) and ORM (object-relational mapper). SQLAlchemy 2.0+ uses typed mappings, select() style queries, and full async support.
Installation
uv add sqlalchemy
uv add alembic # database migrations
uv add asyncpg # async PostgreSQL driver
uv add psycopg2-binary # sync PostgreSQL driver
uv add aiosqlite # async SQLite driver (dev/testing)
When to Use What
Layer
Best for
ORM (Mapped, Session)
CRUD, domain models, relationships, identity tracking
Core (select, insert)
Complex queries, bulk operations, reports
text()
Raw SQL when ORM/Core is overkill
Async (AsyncSession)
FastAPI, async web frameworks, high-concurrency apps
Section Map
File
Topics
01 Engine & Models
Engine, DeclarativeBase, Mapped, mapped_column, column types
02 Relationships & Queries
One-to-many, many-to-many, CRUD, select, join, filtering
03 Sessions & Transactions
Session lifecycle, transactions, unit of work, context managers
04 Async Patterns
AsyncEngine, AsyncSession, loading strategies, FastAPI integration
05 Alembic Migrations
Setup, auto-generate, operations, versioning, async migrations
06 Advanced Recipes
Hybrid properties, events, connection pooling, testing, performance
Quick Start
from sqlalchemy import create_engine , select
from sqlalchemy.orm import DeclarativeBase , Mapped , Session , 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 )
engine = create_engine ( "sqlite:///app.db" , echo = True )
Base . metadata . create_all ( engine )
with Session ( engine ) as session :
session . add ( User ( name = "Alice" , email = "alice@example.com" ))
session . commit ()
stmt = select ( User ) . where ( User . name == "Alice" )
user = session . scalars ( stmt ) . one ()
print ( user . email )
Common Column Types
Python type
SQLAlchemy type
DB type
int
Integer
INTEGER
str
String(n)
VARCHAR(n)
str (unbounded)
Text
TEXT
float
Float
FLOAT
bool
Boolean
BOOLEAN
datetime
DateTime
TIMESTAMP
date
Date
DATE
Decimal
Numeric(p, s)
NUMERIC
bytes
LargeBinary
BLOB
uuid.UUID
Uuid
UUID (PG) / CHAR(32)
dict / list
JSON
JSON / JSONB
Quick Rules
Use 2.0 style — Mapped[], mapped_column(), select().
Keep sessions short-lived — one per request or unit of work.
Never share sessions across threads — use scoped_session or async.
Use selectinload/joinedload — avoid N+1 queries.
Alembic for migrations — never use metadata.create_all() in production.
Use connection pooling defaults — tune pool_size and max_overflow for load.
Prefer session.scalars() — returns ORM objects directly, cleaner than .execute().scalars().
See also
databases
libraries
python
sqlalchemy