The following page contains benchmark results for server-side rendering of dynamic pages in Next.js 15.0.4.
The goal of this test is to demonstrate how well the Next.js server can handle a large number of concurrent requests.
If you wish, you can run this test locally by following the instructions in the README.md.
The benchmark sends concurrent requests to several pages.
Each page renders a list of 10,000 items.
Each page is rendered dynamically for every incoming request.
Route path | Served by | Description |
---|---|---|
/next-app-router | App Router | Server Component Page |
/next-pages-router | Pages Router | Regular Page |
/react | Custom Server | Regular React 19 rendering |
/use-client-route | App Router | Page with use client on top of it |
I used two different benchmarking tools to generate concurrent requests:
During the test, the Next.js server was run on Node.js v22 inside a Docker container with 2 CPU cores and 2 GB of RAM.
During this test, I sent 500 requests in total to each page with a concurrency limit of 50 requests.
Document Path | /next-app-router | /next-pages-router | /react | /use-client-route |
---|---|---|---|---|
Document Length | 960702 bytes | 330067 bytes | 328957 bytes | 333192 bytes |
Concurrency Level | 50 | 50 | 50 | 50 |
Time taken for tests | 43.977 seconds | 6.965 seconds | 2.632 seconds | 8.993 seconds |
Complete requests | 500 | 500 | 500 | 500 |
Failed requests | 0 | 0 | 0 | 0 |
Total transferred | 480508000 bytes | 165174500 bytes | 164516000 bytes | 166753000 bytes |
HTML transferred | 480351000 bytes | 165033500 bytes | 164478500 bytes | 166596000 bytes |
Requests per second | 11.37 #/sec | 71.79 #/sec | 189.99 #/sec | 55.60 #/sec |
Time per request | 87.953 [ms] (mean, across all concurrent requests) | 13.930 [ms] (mean, across all concurrent requests) | 5.263 [ms] (mean, across all concurrent requests) | 17.986 [ms] (mean, across all concurrent requests) |
Transfer rate | 10670.36 [Kbytes/sec] received | 23159.24 [Kbytes/sec] received | 61047.68 [Kbytes/sec] received | 18107.84 [Kbytes/sec] received |
Connection time [ms] min | 113 | 33 | 10 | 49 |
Connection time [ms] mean | 4192 | 658 | 250 | 854 |
Connection time [ms] median | 4398 | 683 | 253 | 872 |
Connection time [ms] max | 4620 | 768 | 312 | 1024 |
The Artillery test shows the same results but also includes charts.
Route path | Sent Requests | Received Responses |
---|---|---|
/next-app-router | link | link |
/next-pages-router | link | link |
/react | link | link |
/use-client-route | link | link |
It appears that pages served by the App Router can handle fewer requests than those served by the Pages Router.
It is also interesting to note that when we add the use client
directive to an App Router page, it can handle more requests per second.
I believe there is room for improvement.