FastAPI async en producción: patrones que sí funcionan
Cinco patrones que extrajimos después de operar APIs FastAPI con tráfico real durante 3 años. Lo que aprendimos a las malas.
Contexto
FastAPI es nuestro stack default para APIs B2B desde 2023. Después de varios proyectos, estos son los patrones que adoptamos como estándar.
1. SQLAlchemy 2.0 + asyncpg
SQLAlchemy 2.0 con dialecto async es la combinación que mejor escala. Evita los ORMs livianos como Tortoise: cuando necesitas un join complejo o una migración no trivial, el ecosistema de Alembic es insustituible.
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
engine = create_async_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
async_session = async_sessionmaker(engine, expire_on_commit=False)
expire_on_commit=False evita queries innecesarias después del commit. pool_pre_ping=True detecta conexiones colgadas antes de que rompan tus endpoints.
2. Dependencies para todo (no globals)
Usa Depends() para db, current_user, configuraciones. Hace los tests 10x más fáciles porque puedes overridear con app.dependency_overrides.
async def get_db():
async with async_session() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
Commit automático al salir del context. Rollback si excepción. Tu router solo hace db.add(x), db.flush() y se preocupa por la lógica.
3. Background tasks > Celery (la mayoría del tiempo)
Para emails, notificaciones, regenerar caches: BackgroundTasks de FastAPI alcanza. Solo introduce Celery cuando necesites:
- Reintentos automáticos con backoff
- Tareas programadas (cron)
- Procesos de larga duración (>30s)
Celery agrega Redis + workers + monitoring. Es overhead grande para "mandar un email después de crear un usuario".
4. Response envelope estándar
Todos nuestros endpoints retornan:
{
"success": true,
"data": { ... },
"message": "...",
"meta": { "page": 1, "per_page": 20, "total": 50 }
}
Frontends saben qué esperar. Los errores van con success: false y el frontend tiene un único path de manejo de errores.
5. Pydantic v2 para validación, dataclasses para internal
Pydantic en los bordes (request/response). Para objetos internos (servicios, helpers), dataclasses o tipos simples. Pydantic es más caro de instanciar de lo que crees; no lo uses para todo.
Lo que NO recomendamos
- Usar SQLAlchemy ORM sin entender SQL: vas a generar consultas N+1 sin darte cuenta
- Usar
async defsin async I/O dentro: estás bloqueando el event loop sin beneficio - Inicializar conexiones en cada request: usa pool con
create_async_engine
Cierre
FastAPI funciona muy bien en producción si entiendes lo que async hace. Si tu equipo viene de Django sync, considera un período de aprendizaje formal antes de soltar al mundo.
Si quieres una segunda opinión sobre tu arquitectura FastAPI, conversemos.