Dev Time Run Time e18e.dev Blog

Run Time Stats

Client Side Rendered Tests

First Paint (ms)

First Paint (ms) chart
Framework First Paint FCP INP
Astro 92ms 91.96ms 2.26ms
Next.js 347ms 346.94ms 17.68ms
Nuxt 157ms 156.96ms 8.21ms
React Router 120.4ms 120.44ms 14.59ms
SolidStart 101.2ms 101.16ms 18.96ms
SvelteKit 104.8ms 104.68ms 11.18ms
TanStack Start 165.8ms 165.85ms 31.94ms

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, TanStack Start, and React Router default to SSR with no per-route opt-out. Next.js wraps the client-side rendered table in a dynamic import with ssr: false to prevent build-time prerendering. TanStack Start uses its built-in spa mode. React Router disables SSR entirely via ssr: false in its config. All other frameworks (Nuxt, SvelteKit, SolidStart, Astro) disable SSR per-route without a separate build.
  • 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

First Paint (ms)

First Paint (ms) chart
Framework First Paint FCP INP
Astro 68.8ms 68.72ms 0.52ms
Next.js 137.6ms 137.48ms 17.9ms
Nuxt 96.4ms 96.38ms 9.8ms
React Router 159.2ms 159.32ms 18.21ms
SolidStart 98.8ms 98.65ms 19.2ms
SvelteKit 74.6ms 74.65ms 0.62ms
TanStack Start 125ms 124.84ms 36.57ms

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

Ops/sec

Ops/sec chart
Framework Ops/sec Median Latency Body Size Duplication
Baseline HTML 833 1.202ms 96.81kb 1x
Astro 581 1.713ms 99.86kb 1x
Mastro 505 1.986ms 181.95kb 1x
Next.js 225 4.635ms 199.11kb 2x
Nuxt 374 2.584ms 201.26kb 2x
React Router 132 7.24ms 211.14kb 2x
SolidStart 400 2.473ms 228.11kb 2x
SvelteKit 429 2.264ms 183.55kb 2x
TanStack Start 315 3.132ms 193.53kb 2x

Methodology

  • Each framework renders a table of 1000 rows with two UUID columns
  • Mock HTTP requests bypass TCP overhead for accurate rendering measurement
  • 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
  • Astro, Nuxt, and SvelteKit handle Node.js HTTP requests natively. React Router, SolidStart, and TanStack Start use Web APIs internally, so benchmarks include the cost of their Node.js adapter layers (@react-router/node, h3, and srvx respectively)
  • Next.js defaults to React Server Components (RSC), a different rendering model than traditional server-rendered React. To keep the comparison fair, Next.js uses "use client" to opt out of RSC and use traditional server rendering + hydration like most of the other frameworks
  • Inspired by eknkc/ssr-benchmark

Server Side Load Test

P99 Latency

P99 Latency at 25 Connections

P99 Latency at 25 Connections chart

P90 Latency

P90 Latency at 25 Connections

P90 Latency at 25 Connections chart
Framework Peak req/s Peak Connections P99 @ 25 P99 @ 50 P99 @ 100 Total Req.
Baseline HTML 5,931.6 200 6ms 11ms 25ms 147,139
Astro 684.6 10 66ms 185ms 2102ms 20,771
Next.js 39 5 2123ms 4636ms 4749ms 1,054
Nuxt 63.4 5 2178ms 4264ms 4346ms 2,005
React Router 65.41 10 2415ms 3901ms 3863ms 2,181
SolidStart 62.2 10 3560ms 3755ms 4265ms 2,030
SvelteKit 540.6 25 79ms 397ms 2204ms 17,256
TanStack Start 43.6 10 3830ms 4566ms 4631ms 1,323

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