Async vs Sync Endpoints
If you have worked with FastAPI or JavaScript before, you might be wondering why we defined our endpoints using standard synchronous functions (def) instead of asynchronous functions (async def).
FastAPI supports both! You can mix and match them depending on what your endpoint needs to do.
When to use async def
You should use async def when your endpoint needs to await other operations. This typically happens when you are making network requests (like calling a third-party API) or using asynchronous libraries.
import asyncio
from fastapi import FastAPI
app = FastAPI()
@app.get("/slow-task")
async def slow_task():
# We must use `await` when calling async functions
await asyncio.sleep(2)
return {"message": "Task complete"}
If an endpoint is defined with async def, FastAPI runs it directly in its primary asynchronous event loop.
When to use def
If you define your endpoint with standard def, FastAPI is smart enough to recognize it. Instead of blocking the main event loop (which would cause your entire server to freeze and stop accepting new requests), FastAPI automatically runs the function in an external threadpool.
import time
from fastapi import FastAPI
app = FastAPI()
@app.get("/sync-task")
def sync_task():
# This is a synchronous, blocking call!
# Because we used `def`, FastAPI safely runs this in a separate thread.
time.sleep(2)
return {"message": "Task complete"}
Our Choice for this Course
Throughout this course, you'll primarily see us using standard synchronous def for our endpoints.
Why?
When we add our database layer using SQLModel, the underlying SQLAlchemy core supports asynchronous operations via the asyncio extension. But writing async queries introduces significant complexity:
- You must manage async sessions and engines.
- You cannot easily rely on lazy-loading relationships (accessing
project.tasksoutside of a query can raise errors if the event loop is blocked). - Error tracebacks can become much harder to read.
By using synchronous database calls and standard def endpoints, FastAPI's threadpool handles the concurrency for us, keeping our code clean, readable, and easy to debug.