Todos los posts
backendfastapiperformance

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.

Samuel Fuentes29 de junio de 20261 min de lectura
FastAPI async en producción: patrones que sí funcionan

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 def sin 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.

¿Te gustó este post? Hablemos.

Si tu empresa tiene un desafío similar, agenda 30 minutos con el equipo. Sin compromiso.

Agendar reunión
Agendar reunión de 30 min