Introduction
If you’re new to FASTAPI, you’ve probably seen both sync and async endpoints and wondered which one is correct. The truth is: both are right — but only in the right situations.
In this blog, I’ll explain what sync and async actually mean in FASTAPI, when to use each approach, and why choosing the right one can dramatically improve your API’s performance.
Sync vs Async
When your application is sequential, CPU-bound, or needs to execute step by step with minimal dependence on external I/O operations, using Sync is perfectly fine. Sync code is simpler, easier to understand, and works well when every request can finish its work without waiting for external systems.
On the other hand, Async becomes useful when you need high-scale performance and your application must handle many concurrent users. If your code frequently waits for I/O operations like database queries, calling external APIs, or reading files. Async allows the server to switch to another request while one is waiting, improving overall throughput and responsiveness.
When exactly to choose Sync?
Choose Sync when your application logic is mostly CPU-bound, straightforward, and involves operations that complete quickly without long waiting on external systems. Sync code is simple, readable, and works perfectly for most low to medium-traffic applications — even if they include database calls.
It’s important to note that sequential business logic is not a Sync feature.
Whether you write sync or async, the order of steps (e.g., payment → save order → deliver) is always defined by your business rules, not by the programming model.
However, Sync often feels more natural for such sequential workflows because:
- The code is easier to write and debug
- The mental model is straightforward
- There’s no need to think about event loops or concurrency
Sync is a good fit when:
- Your API handles moderate traffic
- Your workflows run step-by-step, but without heavy external delays
- You want to keep the codebase simple and maintainable
- Database calls are fast and your system doesn’t require high concurrency
Real-World Example Where Sync works perfectly here
A typical order-processing API follows a business-driven sequence:
- Validate the input
- Process payment
- Save the order
- Trigger delivery
Even though this includes database operations, the flow depends on correctness, not concurrency. For applications with practical traffic levels, a Sync API is more than sufficient.
@app.post("/purchase")
def purchase(order: Order):
payment_status = process_payment(order) # Must happen first
if not payment_status.success:
return {"status": "failed"}
save_order_to_db(order) # Next step in the business flow
trigger_delivery(order) # Final step
return {"status": "success"}
In cases like this, using Sync keeps the code clean and easy to reason about, without sacrificing performance at typical usage levels.
Beginner takeaway
If your API does quick validations and database operations in a fixed sequence, sync FastAPI endpoints are simple, clean, and perfectly sufficient.
When to Choose Async
Use async only when your API spends time waiting (network / I/O), not when it is just doing logic + DB work.
Real-World Example Where Async is the Correct Choice
Example: Bulk Order Status Tracking Dashboard
Scenario
Your online store has:
- An admin dashboard
- Shows live order statuses
- Pulls data from multiple external systems
For each order, the API must
- Call a payment gateway API for payment status
- Call a shipping partner API for delivery status
- Call a warehouse API for stock updates
Each call is slow and independent.
Async shines when you are waiting on multiple slow external systems, not when you are simply saving data.
Conclusion
Sync – CRUD, validations, DB writes, low–medium traffic
Async – External APIs, dashboards, notifications, integrations