โ All frameworks Dev Time Performance
| Prod Deps | Dev Deps | Dup. Deps | node_modules | node_modules (prod) | Dep Install Size | Graph |
| 6 | 8 | 9 | 106.86MB | 17.27MB | 102.22MB | View |
| Metric | Avg | Min | Max |
| Install | 1.21s | 1.20s | 1.23s |
| Cold Build | 1.71s | 1.66s | 1.80s |
| Warm Build | 1.72s | 1.68s | 1.76s |
Build output size: 0.38MB
Duplicate Dependencies
9 duplicate dependencies
detected across this starter's node_modules.
View 9 duplicate dependencies
- debug
[duplicate dependency] debug has 2 installed versions:
4.4.3 via the following 4 package(s) @babel/traverse@7.29.0, @babel/core@7.29.0, vite-node@3.2.4, vite-tsconfig-paths@5.1.4
2.6.9 via the following 6 package(s) body-parser@1.20.4, express@4.22.1, finalhandler@1.3.2, send@0.19.2, compression@1.8.1, morgan@1.10.1
๐ก Suggestions
- Consider standardizing on version 2.6.9 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- semver
[duplicate dependency] semver has 2 installed versions:
6.3.1 via the following 3 package(s) @babel/helper-compilation-targets@7.28.6, @babel/core@7.29.0, @babel/helper-create-class-features-plugin@7.28.6
7.7.4 via the following 1 package(s) @react-router/dev@7.10.1
๐ก Suggestions
- Consider standardizing on version 6.3.1 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- pathe
[duplicate dependency] pathe has 2 installed versions:
1.1.2 via the following 1 package(s) @react-router/dev@7.10.1
2.0.3 via the following 2 package(s) pkg-types@2.3.0, vite-node@3.2.4
๐ก Suggestions
- Consider standardizing on version 2.0.3 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- negotiator
[duplicate dependency] negotiator has 2 installed versions:
0.6.3 via the following 1 package(s) accepts@1.3.8
0.6.4 via the following 1 package(s) compression@1.8.1
๐ก Suggestions
- Consider upgrading consuming packages as this may resolve this duplicate version.
- safe-buffer
[duplicate dependency] safe-buffer has 2 installed versions:
5.1.2 via the following 1 package(s) basic-auth@2.0.1
5.2.1 via the following 3 package(s) content-disposition@0.5.4, express@4.22.1, compression@1.8.1
๐ก Suggestions
- Consider standardizing on version 5.2.1 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- on-finished
[duplicate dependency] on-finished has 2 installed versions:
2.4.1 via the following 4 package(s) body-parser@1.20.4, finalhandler@1.3.2, express@4.22.1, send@0.19.2
2.3.0 via the following 1 package(s) morgan@1.10.1
๐ก Suggestions
- Consider standardizing on version 2.4.1 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- mime-db
[duplicate dependency] mime-db has 2 installed versions:
1.54.0 via the following 1 package(s) compressible@2.0.18
1.52.0 via the following 1 package(s) mime-types@2.1.35
๐ก Suggestions
- Consider upgrading consuming packages as this may resolve this duplicate version.
- ms
[duplicate dependency] ms has 2 installed versions:
2.0.0 via the following 1 package(s) debug@2.6.9
2.1.3 via the following 2 package(s) send@0.19.2, debug@4.4.3
๐ก Suggestions
- Consider standardizing on version 2.1.3 as this version is the most commonly used.
- Consider upgrading consuming packages as this may resolve this duplicate version.
- cookie
[duplicate dependency] cookie has 2 installed versions:
0.7.2 via the following 1 package(s) express@4.22.1
1.1.1 via the following 1 package(s) react-router@7.10.1
๐ก Suggestions
- Consider upgrading consuming packages as this may resolve this duplicate version.
Runtime Performance
Client Side Rendered Tests
| Framework | First Paint | FCP | INP |
| React Router | 155.4ms | 155.62ms | 15.52ms |
Methodology
- Each framework renders a table of 1000 rows with two UUID columns
-
Measured using Lighthouse flow with Chromium via Puppeteer for accurate
browser metrics
-
First Paint and First Contentful Paint are measured on initial navigation
-
Interaction to Next Paint is measured by clicking the first row's detail
link
- Benchmarks run 5 times and results are averaged
-
Next.js wraps the client-side rendered table in a
dynamic import
with ssr: false to prevent build-time prerendering
- TanStack Start, Nuxt, SvelteKit, and SolidStart disable SSR per-route
-
React Router uses route-level
clientLoader functions with HydrateFallback so the client-rendered routes are not server-rendered
- Astro uses client-only React islands for client-side rendered routes
-
Client-side rendered tests use each framework's normal production build
because SPA-only build modes are not supported consistently across the
frameworks being compared
-
Astro uses React for its client-side rendered test: the benchmark table and
detail components are React islands rendered with
client:only="react", which prevents Astro from server-rendering those components and lets them
render only in the browser. Astro's ClientRouter is not used for
this CSR test because it enables client-side transitions and soft navigation behavior
rather than client-only rendering.
Server Side Rendered Tests
| Framework | First Paint | FCP | INP |
| React Router | 95.6ms | 95.55ms | 20.62ms |
Methodology
- Each framework renders a table of 1000 rows with two UUID columns
-
Measured using Lighthouse flow with Chromium via Puppeteer for accurate
browser metrics
-
First Paint and First Contentful Paint are measured on initial navigation
-
Interaction to Next Paint is measured by clicking the first row's detail
link
- Benchmarks run 5 times and results are averaged
-
The measured route is
/server-side-rendered, and detail
navigation uses /server-side-rendered/:id.
Server Side Throughput Tests
| Framework | Ops/sec | Median Latency | Body Size | Duplication |
| Baseline HTML | 841 | 1.206ms | 96.83kb | 1x |
| React Router | 345 | 2.868ms | 211.63kb | 2x |
Methodology
-
Each framework renders the dedicated
/ssr-throughput route with a
table of 1000 rows and UUID id/name columns
-
This route intentionally does not render the exact same table as the browser
SSR and load tests: it omits detail links and framework link components so
router, prefetch, and navigation metadata do not dominate the
request-handler throughput measurement
-
Mock HTTP requests bypass TCP overhead so this measures request-handler
rendering throughput rather than full server throughput
- Data is loaded asynchronously to simulate real-world data fetching
-
Duplication factor indicates how many times each UUID appears in the
response (1x = optimal, 2x = includes hydration payload)
-
Benchmarks run for 10 seconds using tinybench
-
Frameworks are invoked through their production request handlers where
possible. Web API handlers are called with
Request objects; Node.js
handlers are called with mock IncomingMessage and ServerResponse objects.
-
Next.js renders the throughput table as a client component, matching the
setup from PR #94, so the benchmark compares traditional server-rendered
React + hydration work instead of making Next.js render every table row as
React Server Components
-
Inspired by eknkc/ssr-benchmark
Server Side Load Test
| Framework | Peak req/s | Peak Connections | P99 @ 25 | P99 @ 50 | P99 @ 100 | Total Req. |
| Baseline HTML | 1,629.8 | 50 | 20ms | 44ms | 107ms | 48,210 |
| React Router | 176 | 50 | 269ms | 1633ms | 3971ms | 5,724 |
Methodology
-
Each framework serves the server-rendered table route over a real local HTTP
server
-
The measured route is
/server-side-rendered, using the same
1000-row UUID table as the SSR request throughput and browser rendering
tests
-
Load is applied in staged connection counts, from 1 through 200 concurrent
connections, with each stage running for approximately 5 seconds
-
Peak requests/sec is the highest successful stage throughput observed during
the staged run
-
P90 and P99 latency are compared at the 25-, 50-, and 100-connection stages
for every framework, so latency is measured under the same concurrency
pressure
-
Total requests cover the full staged load run, not only the peak stage