Difficulty: Intermediate
When should you use async def vs def for FastAPI route handlers?
Use `async def` when the route performs I/O-bound operations that support async: async database drivers (asyncpg, motor, tortoise-orm), httpx async HTTP client, async file I/O, etc. This allows FastAPI to handle other requests while waiting.
Use `def` (sync) when the code uses blocking libraries (requests, psycopg2, standard file I/O). FastAPI automatically runs sync route handlers in a thread pool so they don't block the event loop.
The problem: Calling a blocking library inside `async def` blocks the event loop for all requests. Always use async alternatives in async routes.
Rule of thumb: If in doubt and you're using a blocking library, use `def`. FastAPI handles thread pool execution automatically.
import httpx
import requests
from fastapi import FastAPI
app = FastAPI()
# GOOD: async route with async HTTP client
@app.get("/async-fetch")
async def fetch_async():
async with httpx.AsyncClient() as client:
response = await client.get("https://api.example.com/data")
return response.json()
# GOOD: sync route with blocking library - runs in thread pool
@app.get("/sync-fetch")
def fetch_sync():
response = requests.get("https://api.example.com/data")
return response.json()
# BAD: blocking call inside async def - blocks event loop!
@app.get("/bad")
async def bad_route():
response = requests.get("https://api.example.com/data") # BLOCKS!
return response.json()
async/await, ASGI, concurrency, blocking I/O