FastAPI, minus the slow.
A fork of FastAPI 0.141.1 that does less work per request: the same public API and test suite, with the plain JSON route down from 31.2 to 15.8 µs on uvicorn and 8.5 µs on granian.
Site: https://notslowapi.com
Docs: https://notslowapi.com/docs/
Source: https://github.com/4thel00z/notslowapi
Install
uv add notslowapi[granian]
pip install "notslowapi[granian]"
Python 3.10 to 3.14 and pydantic>=2.9.0. Pydantic v1 is not supported. The base install brings no ASGI server; the granian extra adds granian>=2.0. The standard extra is FastAPI's and pulls the same set upstream does. Nothing is installed under the fastapi or starlette names, and existing installs of those packages are left alone.
Switch
from notslowapi import FastAPI
Replace the package name fastapi with notslowapi in every import.
Run
granian --interface asgi --workers 1 --loop uvloop myapp:app
myapp:app is the module path and attribute of your FastAPI instance. granian's I/O runs on Rust threads alongside the Python thread, so the framework's Python is the only thing left on the critical path. On a bare ASGI callable the server alone costs 7.8 µs per request under granian against 13.5 µs under uvicorn, and the notslowapi route adds 0.6 µs on top of that under granian against 2.4 µs under uvicorn.
On uvicorn, install uvicorn[standard] for uvloop and httptools (15.8 µs on the plain route against 64.0 µs on asyncio and h11) and run:
uvicorn myapp:app --loop uvloop --http httptools --no-proxy-headers --no-server-header --no-date-header
Leave --proxy-headers on if a proxy in front of you sets X-Forwarded-* headers and your app reads them.
Numbers
One core (Apple M3 Pro, Python 3.13), 64 keep-alive connections, median of 3 x 5 s oha runs, one worker. The first column is upstream FastAPI 0.141.1 on uvicorn at the start of the work; the other two are the current master (all 37 changes). Raw files: bench/baseline/results_ladder_v1.json and results_ladder_v4.json in the repository.
| route | day one, uvicorn (FastAPI 0.141.1) | notslowapi, uvicorn | notslowapi, granian |
|---|---|---|---|
| raw ASGI app, fixed bytes (server floor) | 13.7 µs, 73,040 req/s | 13.4 µs, 74,846 req/s | 7.9 µs, 126,443 req/s |
| plain JSON route | 31.2 µs, 32,033 req/s | 15.8 µs, 63,374 req/s | 8.5 µs, 117,318 req/s |
| int path + str query param | 57.0 µs, 17,531 req/s | 18.3 µs, 54,769 req/s | 9.0 µs, 111,149 req/s |
| pydantic body + response_model | 52.1 µs, 19,212 req/s | 21.1 µs, 47,445 req/s | 14.1 µs, 71,011 req/s |
| 50 routes via include_router | 92.2 µs, 10,842 req/s * | 16.7 µs, 59,862 req/s | 8.5 µs, 117,379 req/s |
| three dependencies (path, header, query via Depends) | not measured | 25.0 µs, 39,953 req/s | 14.9 µs, 67,232 req/s |
* This rung did not exist in results_ladder_v1.json. The 92.2 µs is the before-run of the include_router change (bench/baseline/results_fix11_before.json), measured on a tree that already had the first ten changes, so it understates the day-one gap.
The changes are inside the framework: parameter extraction, the dependency solver, routing, exception handling and response encoding. Each is one commit with a before and after measurement, listed at What changed. The method, the tools and the raw files are at Benchmark method; the full tables are at notslowapi.com/benchmarks/.
Compatibility
notslowapi has the public API of FastAPI 0.141.1: classes, functions, parameters and behaviors are upstream's, and the changes are internal. The check is the upstream test suite with its imports rewritten: 4,563 tests pass, and the three files that need packages this repo does not install (fastapi-cli, strawberry, the OpenTelemetry SDK) are skipped. The modified Starlette 1.6.0 ships inside the package as notslowapi.starlette and nothing is installed under the starlette name, so code that imports starlette.* directly needs upstream Starlette installed and gets upstream behavior for those objects.
from notslowapi.starlette.middleware.base import BaseHTTPMiddleware
from notslowapi.starlette.responses import Response
Two observable differences: AsyncExitStackMiddleware is importable but no longer installed, so the scope no longer carries fastapi_middleware_astack, and solve_dependencies raises RuntimeError instead of failing an assert when a yield dependency runs without an exit stack. Details at Compatibility.
Reporting a regression
Open an issue at github.com/4thel00z/notslowapi/issues with the notslowapi version, a minimal app, and what FastAPI 0.141.1 does with the same code. For a performance regression, name the machine, Python version and server, and attach bench/out/results.json from a before and an after run of the ladder.
Credits
notslowapi is built from FastAPI by Sebastián Ramírez and Starlette by Encode. The code is theirs; this fork changes how much of it runs per request. FastAPI's documentation applies to notslowapi with the package name swapped.
License
The FastAPI code is MIT licensed, copyright 2018 Sebastián Ramírez (LICENSE). The vendored Starlette is BSD-3-Clause, copyright 2018 Encode OSS Ltd (notslowapi/starlette/LICENSE.md). Both files ship in the wheel; the package metadata declares MIT.
Metadata
Release files for notslowapi 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| notslowapi-0.2.0.tar.gz | 565.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| notslowapi-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 783.7 kB
Release files / notslowapi-0.2.0.tar.gz
| Download URL | notslowapi-0.2.0.tar.gz |
|---|---|
| Size | 565.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7e1c2546e3352db67de0926c9ca095ecd73bde4fe045dc5b9ba1959d6344d74b
|
|
BLAKE2b-256 checksum How to use checksums |
ca9b8ac6125c0ae5858429d9ac972fecab91902a4eed73a8211b9b35a0773ceb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logRelease files / notslowapi-0.2.0-py3-none-any.whl
| Download URL | notslowapi-0.2.0-py3-none-any.whl |
|---|---|
| Size | 217.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0c0f31864e3772ecb07fd98c69279c0cc351a68fce73553091c7700706a8e1e4
|
|
BLAKE2b-256 checksum How to use checksums |
3751f68c63b39b78c4fadc6e03a2252e382e48339db800c30f8d2e307b9eef24
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency log