π This is home for "Next.js is my main web server for all APIs. And I like it!" presentation, code examples and benchmark I did.
apps contain monorepo with few apps which I've created while working on this presentation.
I also used them for the benchmark the Next.js as web-server performance π
To run all of them:
pnpm i
pnpm start
They will run respectively on ports:
- nextjs-raw-api-handlers: 3009
- nextjs-raw-route-handlers: 3010
- next-connect-usage: 3011
- nextjs-request-pattern-matching: 3012
- fastify-example: 3013
Benchmarks were made with AutoCannon with the following params:
-c 100
- 100 concurrent connections-d 40
- 40 seconds duration-p 10
- 10 pipelining factor (the number of pipelined requests for each connection. So sending multiple requests at the same time without waiting for the response.)
It tested GET /api/posts
route with simple auth based on JWT.
- Auth middleware code was same for each project.
- Same JWT token was used for each benchmark.
npx autocannon -c 100 -d 40 -p 10 <SERVICE_URL>/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Just run it via npm script
pnpm benchmark <SERVICE_URL>/api/posts
All tests were made on the same machine:
- CPU: Apple M1
- RAM: 16 GB
- macOS: Ventura 13.4
- node.js: v20.10.0
- using
app
and route handlers
β benchmarks git:(master) β npx autocannon -c 100 -d 40 -p 10 localhost:3010/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Running 40s test @ http://localhost:3010/api/posts
100 connections with 10 pipelining factor
βββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg β Stdev β Max β
βββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββΌββββββββββββΌββββββββββββΌββββββββββ€
β Latency β 349 ms β 425 ms β 892 ms β 908 ms β 532.85 ms β 503.32 ms β 9897 ms β
βββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄ββββββββββββ΄ββββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββΌββββββββββ€
β Req/Sec β 765 β 765 β 1,696 β 1,980 β 1,733.4 β 199.38 β 765 β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββΌββββββββββ€
β Bytes/Sec β 2.97 MB β 2.97 MB β 6.57 MB β 7.68 MB β 6.72 MB β 773 kB β 2.96 MB β
βββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
# of samples: 40
71k requests in 40.03s, 269 MB read
270 errors (270 timeouts)
- using
app
and route handlers - wrap route handlers with
next-connect
β benchmarks git:(master) β npx autocannon -c 100 -d 40 -p 10 localhost:3011/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Running 40s test @ http://localhost:3011/api/posts
100 connections with 10 pipelining factor
βββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg β Stdev β Max β
βββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββΌββββββββββββΌββββββββββββΌββββββββββ€
β Latency β 443 ms β 491 ms β 990 ms β 995 ms β 565.78 ms β 353.31 ms β 9927 ms β
βββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄ββββββββββββ΄ββββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββ¬βββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌββββββββββ€
β Req/Sec β 760 β 760 β 1,750 β 1,815 β 1,726.85 β 165.77 β 760 β
βββββββββββββΌββββββββββΌββββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌββββββββββ€
β Bytes/Sec β 2.95 MB β 2.95 MB β 6.78 MB β 7.04 MB β 6.69 MB β 643 kB β 2.94 MB β
βββββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββ΄βββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
# of samples: 40
70k requests in 40.04s, 268 MB read
50 errors (50 timeouts)
- using
pages
and API route handlers
benchmarks git:(master) β npx autocannon -c 100 -d 40 -p 10 localhost:3009/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Running 40s test @ http://localhost:3009/api/posts
100 connections with 10 pipelining factor
βββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬βββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg β Stdev β Max β
βββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββΌββββββββββββΌβββββββββββΌββββββββββ€
β Latency β 317 ms β 349 ms β 372 ms β 446 ms β 356.53 ms β 97.84 ms β 4023 ms β
βββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄βββββββββββ΄ββββββββββ
βββββββββββββ¬βββββββββ¬βββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββ¬βββββββββ¬βββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg β Stdev β Min β
βββββββββββββΌβββββββββΌβββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌβββββββββ€
β Req/Sec β 1,994 β 1,994 β 2,801 β 3,001 β 2,795.38 β 224.84 β 1,994 β
βββββββββββββΌβββββββββΌβββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌβββββββββ€
β Bytes/Sec β 7.7 MB β 7.7 MB β 10.8 MB β 11.6 MB β 10.8 MB β 867 kB β 7.7 MB β
βββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββ΄βββββββββ΄βββββββββ
Req/Bytes counts sampled once per second.
# of samples: 40
113k requests in 40.04s, 432 MB read
- using
pages
and API route handlers - exposes single endpoint and uses
ts-pattern
to match requests
β benchmarks git:(master) β npx autocannon -c 100 -d 40 -p 10 localhost:3012/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Running 40s test @ http://localhost:3012/api/posts
100 connections with 10 pipelining factor
βββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg β Stdev β Max β
βββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββΌββββββββββββΌββββββββββββΌββββββββββ€
β Latency β 254 ms β 373 ms β 395 ms β 416 ms β 376.38 ms β 232.65 ms β 6919 ms β
βββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄ββββββββββββ΄ββββββββββββ΄ββββββββββ
βββββββββββββ¬βββββββββ¬βββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββββ¬βββββββββ¬βββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg β Stdev β Min β
βββββββββββββΌβββββββββΌβββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌβββββββββ€
β Req/Sec β 1,864 β 1,864 β 2,645 β 2,945 β 2,644.48 β 195.6 β 1,864 β
βββββββββββββΌβββββββββΌβββββββββΌββββββββββΌββββββββββΌβββββββββββΌβββββββββΌβββββββββ€
β Bytes/Sec β 7.2 MB β 7.2 MB β 10.2 MB β 11.4 MB β 10.2 MB β 755 kB β 7.2 MB β
βββββββββββββ΄βββββββββ΄βββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββββ΄βββββββββ΄βββββββββ
Req/Bytes counts sampled once per second.
# of samples: 40
107k requests in 40.07s, 408 MB read
- using raw
fastify
(withoutfastify-cli
)
β benchmarks git:(master) β npx autocannon -c 100 -d 40 -p 10 localhost:3013/api/posts -H Authorization="Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcmc6bWljaGFsY3p1a206aXNzdWVyIiwiYXVkIjoib3JnOm1pY2hhbGN6dWttOmF1ZGllbmNlIn0.CHaB_qZjIuKMYc487Jscj-KCyj1OuW8-e1R1d1n0KucsF2t_XtXNDzjOk7qowhpVLwF_GBzgUvPYoCi3BUmSyQ"
Running 40s test @ http://localhost:3013/api/posts
100 connections with 10 pipelining factor
βββββββββββ¬ββββββββ¬ββββββββ¬ββββββββ¬ββββββββ¬βββββββββββ¬βββββββββββ¬βββββββββ
β Stat β 2.5% β 50% β 97.5% β 99% β Avg β Stdev β Max β
βββββββββββΌββββββββΌββββββββΌββββββββΌββββββββΌβββββββββββΌβββββββββββΌβββββββββ€
β Latency β 20 ms β 24 ms β 50 ms β 56 ms β 32.26 ms β 13.36 ms β 704 ms β
βββββββββββ΄ββββββββ΄ββββββββ΄ββββββββ΄ββββββββ΄βββββββββββ΄βββββββββββ΄βββββββββ
βββββββββββββ¬ββββββββββ¬ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββββ¬ββββββββββ
β Stat β 1% β 2.5% β 50% β 97.5% β Avg β Stdev β Min β
βββββββββββββΌββββββββββΌββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββββΌββββββββββ€
β Req/Sec β 26,815 β 26,815 β 30,927 β 31,455 β 30,516 β 1,125.28 β 26,812 β
βββββββββββββΌββββββββββΌββββββββββΌβββββββββΌβββββββββΌβββββββββΌβββββββββββΌββββββββββ€
β Bytes/Sec β 90.9 MB β 90.9 MB β 105 MB β 107 MB β 103 MB β 3.8 MB β 90.8 MB β
βββββββββββββ΄ββββββββββ΄ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββββ΄ββββββββββ
Req/Bytes counts sampled once per second.
# of samples: 40
1222k requests in 40.02s, 4.14 GB read