When should a FastAPI route use async def instead of a plain def, and what's the risk?medium
Use async def only when every I/O call inside the route is also non-blocking, such as an async DB driver or httpx.AsyncClient. A plain def route is automatically run in a worker thread pool by FastAPI, so it's the safer default when it calls any blocking or sync code. Calling a blocking library inside async def blocks the entire event loop, stalling every other request on that worker.
FastAPI lets you write either def or async def for the same endpoint and both work, but they behave differently under load. A regular def endpoint runs in a worker thread pool, so it won't block the main event loop even if it does blocking work. An async def endpoint runs directly on the event loop, which is efficient only if everything it awaits is also async. The trap is calling a blocking library (a sync DB driver, requests, etc.) inside an async def function — that blocks the entire event loop and stalls every other request on that worker. Rule of thumb: CPU-light work with all-async I/O (an async DB driver, httpx.AsyncClient) should use async def; anything with a blocking or sync call inside should stay a plain def so FastAPI threads it for you. Interview line: async def isn't automatically faster — it's only faster when every I/O call inside it is also non-blocking.