Async Routes & Databases
Combine async def routes with SQLAlchemy 2.0 async sessions and asyncpg.
Recipe
Quick-reference recipe card - copy-paste ready.
from fastapi import Depends, FastAPI
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy import text
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db", pool_pre_ping=True)
Session = async_sessionmaker(engine, expire_on_commit=False)
app = FastAPI()
async def get_session():
async with Session() as s:
yield s
@app.get("/ping")
async def ping(session: AsyncSession = Depends(get_session)):
await session.execute(text("SELECT 1"))
return {"db": "ok"}When to reach for this:
- High-concurrency I/O APIs
- PostgreSQL with asyncpg
- Non-blocking HTTP upstream calls
Working Example
from sqlalchemy import select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import Depends, FastAPI
class Base(DeclarativeBase):
pass
class Item(Base):
__tablename__ = "items"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column()
# assume Session/get_session from recipe
app = FastAPI()
@app.get("/items")
async def list_items(session: AsyncSession = Depends(get_session)) -> list[dict]:
rows = (await session.execute(select(Item).limit(20))).scalars().all()
return [{"id": r.id, "name": r.name} for r in rows]What this demonstrates:
- Async ORM queries
- Request-scoped sessions
- SQLAlchemy 2.0 select style
Deep Dive
How It Works
- Uvicorn schedules coroutines on an event loop.
- Async engines use asyncpg for PostgreSQL.
- Keep transactions short per request.
Gotchas
- Boundary validation skipped - Invalid data reaches persistence layers.. Fix: Validate with Pydantic or framework forms at the edge..
- Leaking stack traces - Clients see internal errors.. Fix: Map exceptions to stable HTTP responses..
- Blocking async event loops - Workers stall under concurrent load.. Fix: Use async drivers or threadpool wrappers..
- Secrets in source control - Credentials leak via git history.. Fix: Load secrets from env or a vault at runtime..
- Missing observability - Incidents are hard to debug.. Fix: Add structured logs, metrics, and request IDs..
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Alternate framework in this cookbook | Team standard or existing monolith | Greenfield API with different constraints |
| Managed BaaS | CRUD-only MVP | Custom auth, workflows, or compliance needs |
| gRPC | Internal high-performance RPC | Public HTTP clients and browser access |
FAQs
When should I adopt async FastAPI database access?
Use it when the patterns and trade-offs on this page match your API or data boundary.
What is the top production mistake with async FastAPI database access?
Skipping validation, timeouts, or explicit error contracts at the HTTP edge.
How do I test async FastAPI database access?
Use the framework test client, override dependencies, and assert status plus JSON shape.
Does async FastAPI database access work with Python 3.14?
Yes - examples target Python 3.14 with pinned framework versions from the stack footer.
How does async FastAPI database access relate to Pydantic 2?
Validate and serialize at boundaries; keep services working with typed domain objects.
Sync or async?
Prefer async routes when I/O dominates; keep CPU work small or offload to workers.
Where should business logic live?
Thin handlers; services own rules; repositories own queries.
How do I document APIs?
Publish OpenAPI or schema docs that match response models in code.
How do I handle versioning?
Explicit URL or header versioning with deprecation windows - avoid silent breaks.
What should I read next?
Follow the Related links for the next layer of depth in this section.
How do I stay secure?
Authenticate callers, authorize per resource, rate-limit, and never log secrets.
Performance first step?
Measure DB and upstream latency before swapping frameworks.
Related
- FastAPI Basics - Core routes and models
- Dependency Injection - Per-request providers
- Testing FastAPI - Test client patterns
- Deploying FastAPI - Production serving
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.