Performance and Benchmarks

Results

Sync

Why so fast?

  • We utilize msgspec.json.decode() and msgspec.json.encode() to parse json, it is the fastest json parsing tool in Python land

  • We can support msgspec.Struct models, which are faster than pydantic

  • We provide django.urls.path() drop-in Routing replacement which is x51 times as fast as the default one

  • We validate data smartly: we prepare models for validation in advance, so no runtime magic ever happens

  • We have special “production mode” with fewer checks, so we can have the best of two worlds: strict development workflow and fast runtime for real users

Async

While fastapi is faster at the moment, we have several ideas to optimize django-modern-rest even further, so it can be on par (or even faster!) with the fastest python web frameworks in existence.

While keeping 100% of compatibility with the older libs and tools.

Technical details

See source code for our benchmark suite.

Benchmarks!

Important Notice

All benchmarks are always synthetic. Benchmarks do not test real performance, they test ideas of performance.

Environment

  • Python: 3.13.7, no JIT, no free-threading

  • OS: MacOS 15.6.1

  • Device: Apple M2 Pro, mid 2023, 16 Gb of RAM

Assumptions

  • We test only the API part, because django-modern-rest does not include any database features, we want to make sure that the part that we are covering is measured, not something else

  • We test the minimal possible app

  • We use the same exact data for all apps

  • We test production-like setups with DEBUG=False

  • We test both sync (gunicorn) and async (uvicorn) version if the requested mode is supported (yes, DRF, we are looking at you)

  • But, we don’t compare sync to async and vice versa, because they have different logic, different deploy strategies, etc

Results

Async

framework

is_async

rps

tpr

fastapi

True

10854.6

1.843

dmr

True

7026.27

2.846

ninja

True

4359.12

4.588

Sync

framework

is_async

rps

tpr

dmr

False

5774.94

3.463

ninja

False

3888.13

5.144

drf

False

3024.24

6.613

Running the script:

Pre-requirements:

Run from benchmarks/ directory:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
make bench

Manual debug

Single request:

curl -X POST \
  'http://127.0.0.1:8000/async/user/?per_page=1&count=2&page=3&filter=abc' \
  -d @payload.json \
  -H 'Content-Type: application/json' \
  -H 'X-API-Token: some-token-example' \
  -H 'X-Request-Origin: some-origin'

Manual bench:

ab -c 20 -n 1000 -l -p payload.json \
  -H 'X-API-Token: some-token-example' \
  -H 'X-Request-Origin: some-origin' \
  -T 'application/json' \
  'http://127.0.0.1:8000/async/user/?per_page=1&count=2&page=3&filter=abc'

Feature benchmarks

We also benchmark several our features that can be used independently.

Pre-requirements:

path replacement

See our routing guide

make -C benchmarks bench-resolver produces:

Summary
  dmr-best ran
    1.09 ± 0.01 times faster than django-best
    1.55 ± 0.01 times faster than dmr-avg
    1.75 ± 0.01 times faster than django-avg
    1.98 ± 0.02 times faster than dmr-worst
    2.58 ± 0.02 times faster than django-worst