Python FastAPI Tutorial (Part 7): Sync vs Async - Converting Your App to Asynchronous

| Programming | January 17, 2026 | 8.55 Thousand views | 32:10

TL;DR

This tutorial demonstrates converting a FastAPI application from synchronous to asynchronous operations using SQLAlchemy's async extensions, emphasizing that async improves IO-bound task handling but requires mandatory eager loading for database relationships and careful awaiting of specific operations.

Async Fundamentals in FastAPI 3 insights

IO-bound vs CPU-bound distinction

Async improves performance for IO-bound tasks like database queries and external API calls by allowing concurrent work during wait times, but provides no benefit for CPU-bound operations like image processing or heavy calculations.

FastAPI's dual execution model

FastAPI automatically runs synchronous routes in separate thread pools to prevent blocking, while async routes run directly in the main event loop for better efficiency but require explicit awaiting of all IO operations.

Concurrency benefits under load

While async adds slight overhead for simple requests, it significantly improves performance when handling many simultaneous connections by preventing idle waiting.

🗄️ Database Configuration & Setup 3 insights

Async driver installation

Install `aiosqlite` and modify the database URL to `sqlite+aiosqlite:///./database.db` to enable async SQLite support with SQLAlchemy's async extensions.

Engine and session updates

Replace `create_engine` with `create_async_engine` and `sessionmaker` with `async_sessionmaker` from `sqlalchemy.ext.asyncio`, setting `expire_on_commit=False` to prevent lazy loading issues.

Lifespan context manager

Use an async lifespan function with `asynccontextmanager` to handle startup table creation via `engine.begin()` instead of synchronous `Base.metadata.create_all()`, replacing deprecated `on_event` decorators.

🔍 Critical Query Pattern Changes 3 insights

Mandatory eager loading

Async SQLAlchemy does not support lazy loading; use `selectinload()` to explicitly load relationships like `post.author` within queries or the application will throw missing greenlet errors.

Selective awaiting rules

Await `execute()`, `commit()`, `refresh()`, and `delete()` operations, but do not await `add()` which only stages objects in memory without performing IO.

Relationship-aware queries

Every route accessing related data must include eager loading instructions, requiring developers to know in advance which relationships templates or Pydantic responses will traverse.

Bottom Line

When converting FastAPI to async, always use `selectinload` for database relationships, configure `aiosqlite` with `expire_on_commit=False`, and carefully distinguish between IO operations that need awaiting versus in-memory staging that doesn't.

More from Corey Schafer

View all