Back to Blog
Can FastAPI Handle Millions of Orders? Yes, No, and It Depends
fastapipythonbackendasynchronousgenerative-ai

Can FastAPI Handle Millions of Orders? Yes, No, and It Depends

How FastAPI handles high traffic: ASGI vs WSGI, Starlette, Pydantic, async vs def, concurrency vs parallelism, and what really decides scale.

๐Ÿ“š Part 2 of the Ship It series. Missed Part 1? โ€œFastAPI Is Fast.โ€ So Why Is Your API Slow?

Imagine a food-delivery app processing 2 million orders a day.

Sounds huge, right? Grab a calculator:

2,000,000 orders รท 86,400 seconds โ‰ˆ 23 orders per second

Twenty-three. On average, almost any framework can handle that.

So why do high-traffic systems still fall over? Two reasons:

  1. Traffic isn't average. Dinner time can mean several times the average load, all at once.

  2. Most of a request's life is spent waiting on the database, the payment gateway, the restaurant's system, the delivery partner API.

The real question isn't "how fast is my framework?" It's "what does my server do while it waits?"

That's where FastAPI's design gets interesting. Let's open it up. ๐Ÿ”ง


"Fast" means two different things

Kind of fast Where it comes from
Runtime fast An async-capable stack that doesn't sit idle while waiting on I/O
Developer fast Type hints, Pydantic validation, dependency injection, and auto-generated docs

They're related, but don't mix them up. FastAPI doesn't make your Python code run faster. It wastes less time waiting, and it saves you from writing a lot of plumbing.

The thought experiment: an order service

Say the order-processing microservice for our food app is written in a classic synchronous style. For this workload, three things start to hurt:

  • Synchronous request handling by default: a request waiting on the DB holds up its worker

  • Validation is DIY: you bolt on your own checks for every payload

  • Docs are DIY: the frontend team keeps asking "what does this endpoint expect?"

FastAPI's answer to each:

  • โšก Async path operations

  • โœ… Pydantic validation for requests and responses

  • ๐Ÿ“„ Automatic OpenAPI docs

To be fair, Flask is still a great framework for plenty of apps. This is about matching the tool to the workload, not crowning a winner.

What's actually inside FastAPI

FastAPI isn't one giant framework. It's a thin, opinionated layer on top of two solid libraries:

Your API code
      โ†“
   FastAPI      โ† conventions, DI, OpenAPI, developer experience
      โ†“
  Starlette     โ† the web engine: routing, middleware, WebSockets
      โ†“
    ASGI        โ† the contract between server and app
      โ†•
   Uvicorn      โ† the ASGI server

FastAPI
  โ””โ”€โ”€ Pydantic  โ† validation and serialization

Starlette: the web engine

Starlette handles the low-level web work:

  • Routing: /register goes here, /login goes there

  • Middleware: auth checks, headers, CORS, compression, error handling

  • WebSockets: two-way, real-time communication

  • Background tasks: small jobs that run after the response is sent

Pydantic: the bouncer at the door ๐Ÿšช

Pydantic answers one question: does this data match what I expect?

from pydantic import BaseModel, EmailStr

class UserCreate(BaseModel):
    email: EmailStr
    password: str

Wrong type, missing field, or bad email? The request is rejected with a clear error before it reaches your logic. And the same model shows up in your API docs automatically.

๐Ÿ’ก EmailStr needs an extra package: pip install "pydantic[email]"

Opinionated vs unopinionated

Unopinionated Opinionated (FastAPI)
You decide everything Sensible defaults are provided
More freedom, more decisions Less boilerplate, more consistency
Teams invent their own conventions The framework sets the conventions

Opinionated doesn't mean "automatically correct". It means fewer decisions you have to repeat on every project.

WSGI vs ASGI: the heart of it

WSGI ASGI
The traditional synchronous interface An async-capable interface
Built around a simple request โ†’ response Event-driven; supports WebSockets too
A blocked request occupies a worker An async app can await and let other work proceed
Classic Flask deployments FastAPI, Starlette

Here's the picture that made it click for me:

WSGI-style
Worker A โ†’ Request 1 โ†’ waitโ€ฆ โ†’ done
Worker B โ†’ Request 2 โ†’ waitโ€ฆ โ†’ done
Worker C โ†’ Request 3 โ†’ waitโ€ฆ โ†’ done

ASGI-style
One event loop
 โ”œโ”€โ”€ Request 1 โ†’ awaiting DB
 โ”œโ”€โ”€ Request 2 โ†’ awaiting payment API
 โ”œโ”€โ”€ Request 3 โ†’ processing
 โ””โ”€โ”€ Request 4 โ†’ awaiting network

The restaurant model ๐Ÿฝ๏ธ

Component Restaurant role
ASGI server The entrance that lets customers in
Starlette The floor manager who routes customers
FastAPI The house rules that keep everything organised
Pydantic The order checker: "is this order complete?"
Your endpoint The kitchen doing the actual cooking
DB / AI / external APIs Suppliers the kitchen waits on

The big insight: while one order waits for a supplier, the kitchen shouldn't stop cooking every other order.

Concurrency โ‰  parallelism

Concurrency Parallelism
Many tasks make progress by taking turns while others wait Many tasks run at the same time on multiple cores
Great for I/O-bound work (APIs, DBs) Needed for CPU-bound work (heavy maths, ML inference)
async / await Multiple processes

Async doesn't make one worker do 1,000 things at once. It means the worker doesn't sit idle while waiting.

๐Ÿง  Quiz time

Both endpoints call an external API using the popular (synchronous) requests library. Which one is better under load?

import requests
from fastapi import FastAPI

app = FastAPI()

@app.get("/a")
async def endpoint_a():
    r = requests.get("https://example.com/orders")
    return r.json()

@app.get("/b")
def endpoint_b():
    r = requests.get("https://example.com/orders")
    return r.json()

Think about it before scrolling. ๐Ÿ‘‡

.

.

.

Answer: B, the one without async. ๐Ÿ˜ฎ

requests is blocking. Inside async def, it freezes the event loop and every other request waits. A plain def endpoint is run by FastAPI in a threadpool, so the blocking call doesn't stall the loop.

If you want async def, use an async client such as httpx.AsyncClient with await.

Rule of thumb

Your code usesโ€ฆ Use
Async libraries (await-able DB driver, HTTP client) async def
Blocking libraries you can't replace def
Heavy CPU work Separate processes, workers, or a task queue

Did you get it right? Tell me in the comments. ๐Ÿ‘‡

Free docs, zero effort ๐Ÿ“„

Because FastAPI follows the OpenAPI standard, you get these out of the box:

/docs          โ†’ Swagger UI (try endpoints in the browser)
/redoc         โ†’ ReDoc (clean reference docs)
/openapi.json  โ†’ the machine-readable schema

No more Slack threads asking "what fields does this endpoint need?" The contract is generated from your code.

The full request journey

Client
  โ†“
ASGI server (Uvicorn)
  โ†“
Starlette: routing, middleware
  โ†“
FastAPI: dependencies
  โ†“
Pydantic: validation and parsing
  โ†“
Your endpoint
  โ†“
DB / external API / LLM  โ† mostly waiting here
  โ†“
Response serialization
  โ†“
Client

This is exactly why the model fits AI backends so well. An LLM call is a long wait, and an async server can serve other users in the meantime.

Soโ€ฆ can FastAPI handle millions of orders?

Async is one tool, not the whole toolbox. At real scale you combine:

  • Async concurrency for I/O-bound waits

  • Multiple worker processes to use every CPU core:

uvicorn main:app --workers 4
  • Horizontal scaling: more instances behind a load balancer

  • Fast dependencies: indexes, connection pooling, caching, queues

Layer What can sink you
Framework Routing, validation, serialization
ASGI server Connection handling
Database Missing indexes, pool exhaustion, locks
External services Latency, rate limits, missing timeouts
Infrastructure CPU, memory, autoscaling
Architecture No caching, no queues, no observability

So: yes, no, and it depends. FastAPI removes one important class of bottleneck. The rest of the system still has to keep up.

TL;DR

  1. "Fast" means runtime efficiency and developer speed. They're different benefits.

  2. FastAPI = Starlette (web engine) + Pydantic (validation) + OpenAPI (docs), on ASGI.

  3. Async shines when your app spends time waiting.

  4. Concurrency โ‰  parallelism.

  5. Blocking code inside async def is worse than plain def.

  6. Scale = async + workers + horizontal scaling + fast dependencies.

Keep digging


Your turn ๐Ÿ’ฌ

What's the sneakiest blocking call you've found hiding inside an async def? A DB driver, an SDK, a time.sleep someone forgot?

Drop it in the comments. The best ones might show up in a future post. ๐Ÿ‘€

โฌ…๏ธ Previous: โ€œFastAPI Is Fast.โ€ So Why Is Your API Slow? โžก๏ธ Next: coming soon. Follow the series so you don't miss it.

Related Posts

"FastAPI Is Fast." So Why Is Your API Slow?

"FastAPI Is Fast." So Why Is Your API Slow?

FastAPI is fast, but your API can still be slow. Learn how blocking code, bad design and heavy I/O hurt performance, with a quick async quiz.

fastapipythonwebdev+2 more
Read More

A Complete Guide to Integrating Okta OpenID Connect SSO with FastAPI and React

A Complete Guide to Integrating Okta SSO with FastAPI and React Okta is a leading identity management solution that simplifies Single Sign-On (SSO) integration. In this guide, weโ€™ll walk through howโ€ฆ

authenticationreactfastapi+2 more
Read More

Plotly: Bar Charts

This is the 3rd part of my Plotly series. If you havenโ€™t read the previous ones, you can read them here . In this blog, I am going to explain how can we render Bar Charts using Plotly. We are goingโ€ฆ

data-visualizationpythondata-engineering+2 more
Read More

Design & Developed by Ramxcodes
ยฉ 2026. All rights reserved.