Skip to content

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.

Python
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.

Python
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.tasks outside 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.