# FastAPI vs Flask: Performance Benchmarks and Architectural Differences

> Discover FastAPI vs Flask performance benchmarks. FastAPI excels with async support and Pydantic validation, outperforming Flask's synchronous WSGI for high throughput APIs.

- Repository: [Sebastián Ramírez/fastapi](https://github.com/tiangolo/fastapi)
- Tags: performance
- Published: 2026-02-16

---

**FastAPI consistently outperforms Flask in independent TechEmpower benchmarks due to its ASGI foundation, native async/await support, and compiled Pydantic validation, while Flask's WSGI architecture forces synchronous request handling that limits throughput under concurrent load.**

When comparing Python web frameworks for high-performance APIs, understanding the architectural differences between FastAPI and Flask is essential. This analysis examines the `tiangolo/fastapi` repository source code to explain why FastAPI achieves superior performance in independent benchmarks, while highlighting the specific implementation details that give it an edge over Flask's traditional synchronous approach.

## Architectural Foundations: ASGI vs WSGI

The fundamental performance gap between FastAPI and Flask begins at the protocol layer. FastAPI implements the **ASGI** (Asynchronous Server Gateway Interface) standard, while Flask relies on the older **WSGI** (Web Server Gateway Interface) specification.

### FastAPI's Async-First Design

FastAPI is built on **Starlette** and implements the ASGI protocol to enable true asynchronous request handling. In [`fastapi/applications.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/applications.py), the `FastAPI` class inherits from Starlette's application class, allowing endpoints defined with `async def` to run concurrently. This architecture keeps the event loop alive while awaiting I/O operations like database queries or external HTTP calls.

### Flask's Synchronous WSGI Model

Flask relies on the WSGI standard, which processes requests synchronously. Each request blocks the worker thread until completion, preventing concurrent handling within a single worker process. While Flask can achieve concurrency through multiple worker processes or threads, this approach increases memory overhead and context-switching costs compared to FastAPI's single-process async model.

## Performance Benchmarks: TechEmpower Results

The FastAPI documentation explicitly references independent **TechEmpower Benchmarks** to validate its performance claims. According to [`docs/en/docs/benchmarks.md`](https://github.com/tiangolo/fastapi/blob/main/docs/en/docs/benchmarks.md), "Independent TechEmpower benchmarks show **FastAPI** applications running under **Uvicorn** as **one of the fastest Python frameworks available**, only behind Starlette and Uvicorn themselves."

The documentation clarifies the relationship between FastAPI and its underlying framework: "FastAPI uses Starlette, so it cannot be faster than it, but it adds useful features on top without additional runtime cost." When comparing against Flask specifically, the benchmarks categorize Flask alongside other WSGI frameworks, where FastAPI consistently demonstrates higher throughput and lower latency in JSON serialization and database query scenarios.

## Why FastAPI Outperforms Flask

Several implementation details in the FastAPI source code contribute to its superior performance:

**Async I/O Concurrency**
FastAPI endpoints defined with `async def` allow the Uvicorn server to handle thousands of concurrent connections without spawning additional threads. In contrast, Flask blocks the worker process during I/O operations, requiring process pools to achieve similar concurrency levels.

**Lean Routing Engine**
The routing logic in [`fastapi/routing.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/routing.py) leverages Starlette's optimized path matching and dependency resolution. This minimal overhead contrasts with Flask's heavier WSGI middleware stack, which processes each request through multiple layers of indirection.

**Compiled Validation**
FastAPI uses **Pydantic** for request and response validation. Pydantic models compile validation logic at import time using Rust-based parsing, resulting in near-zero runtime overhead. Flask lacks built-in validation, forcing developers to implement manual parsing loops that execute at runtime, adding latency to every request.

**Server Optimization**
FastAPI runs on **Uvicorn**, an ASGI server built on `uvloop` and `httptools` that outperforms traditional WSGI servers used with Flask. The benchmark suite in [`tests/benchmarks/test_general_performance.py`](https://github.com/tiangolo/fastapi/blob/main/tests/benchmarks/test_general_performance.py) measures request latency specifically for FastAPI endpoints running under Uvicorn, validating these performance characteristics.

## Code Comparison: Async vs Sync Implementation

The following examples demonstrate the architectural differences between FastAPI's async/Pydantic approach and Flask's synchronous manual validation.

**FastAPI Implementation**

```python

# fastapi_example.py

from fastapi import FastAPI, Depends
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    value: int


def get_multiplier() -> int:
    return 2


@app.post("/items")
async def create_item(item: Item, multiplier: int = Depends(get_multiplier)):
    # The request body is already validated and parsed into `item`

    total = item.value * multiplier
    return {"name": item.name, "total": total}

```

This implementation leverages the `FastAPI` class from [`fastapi/applications.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/applications.py) and automatic request validation through Pydantic models defined in the endpoint signature.

**Flask Implementation**

```python

# flask_example.py

from flask import Flask, request, jsonify

app = Flask(__name__)

def validate_item(data):
    if not isinstance(data.get("name"), str) or not isinstance(data.get("value"), int):
        raise ValueError("Invalid payload")
    return data["name"], data["value"]

def get_multiplier():
    return 2

@app.route("/items", methods=["POST"])
def create_item():
    try:
        payload = request.get_json()
        name, value = validate_item(payload)
        total = value * get_multiplier()
        return jsonify({"name": name, "total": total})
    except (KeyError, ValueError) as exc:
        return jsonify({"error": str(exc)}), 400

```

Flask requires manual JSON parsing and validation logic, and the endpoint runs synchronously without native support for the `async`/`await` syntax.

## Key Source Files in the FastAPI Repository

The following files in the `tiangolo/fastapi` repository demonstrate the implementation details behind FastAPI's performance characteristics:

| File | Purpose | Link |
|------|---------|------|
| [`fastapi/applications.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/applications.py) | Defines the `FastAPI` class (inherits from Starlette). | <https://github.com/tiangolo/fastapi/blob/master/fastapi/applications.py> |
| [`fastapi/routing.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/routing.py) | Core routing logic used by FastAPI/Starlette. | <https://github.com/tiangolo/fastapi/blob/master/fastapi/routing.py> |
| [`fastapi/params.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/params.py) | Handles request parameters, dependencies, and validation. | <https://github.com/tiangolo/fastapi/blob/master/fastapi/params.py> |
| [`fastapi/testclient.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/testclient.py) | Provides `TestClient` for testing (used in benchmark suite). | <https://github.com/tiangolo/fastapi/blob/master/fastapi/testclient.py> |
| [`docs/en/docs/benchmarks.md`](https://github.com/tiangolo/fastapi/blob/main/docs/en/docs/benchmarks.md) | Official benchmark discussion and links to TechEmpower results. | <https://github.com/tiangolo/fastapi/blob/master/docs/en/docs/benchmarks.md> |
| [`tests/benchmarks/test_general_performance.py`](https://github.com/tiangolo/fastapi/blob/main/tests/benchmarks/test_general_performance.py) | Benchmark suite (run with `--codspeed`) that measures request latency for FastAPI endpoints. | <https://github.com/tiangolo/fastapi/blob/master/tests/benchmarks/test_general_performance.py> |

These files collectively illustrate how FastAPI is engineered for high performance and why it consistently outpaces Flask in real-world API workloads.

## Summary

- **FastAPI** leverages **ASGI** and **Starlette** to enable true asynchronous request handling, while **Flask** relies on synchronous **WSGI** processing that blocks during I/O operations.
- Independent **TechEmpower Benchmarks** demonstrate that FastAPI running on **Uvicorn** ranks among the fastest Python frameworks, significantly outpacing Flask in throughput and latency.
- FastAPI's performance advantages stem from **async I/O concurrency**, **lean routing** in [`fastapi/routing.py`](https://github.com/tiangolo/fastapi/blob/main/fastapi/routing.py), **compiled Pydantic validation**, and optimized **Uvicorn** server integration.
- Flask requires manual validation and synchronous processing, necessitating process pools to achieve concurrency levels that FastAPI handles within a single event loop.

## Frequently Asked Questions

### Is FastAPI always faster than Flask for every type of application?

Not necessarily for CPU-bound workloads. FastAPI excels in I/O-bound scenarios such as database queries, HTTP microservices, and real-time APIs where async/await prevents blocking. However, for simple CPU-intensive tasks without I/O waits, both frameworks perform similarly because the async event loop provides no advantage when computations block the thread regardless.

### Can I run Flask with an ASGI server to match FastAPI's performance?

While adapters like `asgiref` allow Flask to run under ASGI servers, this does not provide true async performance benefits. Flask's internal request handling remains synchronous, so the adapter merely wraps blocking calls without enabling concurrent request processing within a single worker. To achieve comparable concurrency, Flask requires multiple worker processes, increasing memory overhead compared to FastAPI's single-process async model.

### How does Pydantic validation in FastAPI affect performance compared to Flask?

Pydantic provides **zero-runtime-cost** validation after startup because it compiles validation logic into optimized Rust-based parsers during model definition. This means FastAPI validates complex request bodies with minimal latency. In Flask, developers typically implement validation manually using Python loops or libraries like Marshmallow, which execute validation logic at runtime for every request, adding measurable overhead that increases with payload complexity.

### What server should I use to achieve the best FastAPI performance?

For production deployments, run FastAPI with **Uvicorn** (the standard ASGI server) or **Hypercorn**, preferably behind a reverse proxy like Nginx. Uvicorn is built on `uvloop` (a fast Cython event loop) and `httptools` (a C HTTP parser), which significantly outperform traditional WSGI servers like Gunicorn with synchronous workers. The FastAPI benchmark suite in [`tests/benchmarks/test_general_performance.py`](https://github.com/tiangolo/fastapi/blob/main/tests/benchmarks/test_general_performance.py) specifically validates performance using Uvicorn with `--codspeed` instrumentation.