Benchmarks

Local oha runs on the same machine, same window, same runtime version. Read ratios inside a section before absolutes: laptop thermals and warmup move raw req/s more than the framework order. Reproduce with bun run bench:ssr and bun run bench:http.

Full-stack SSR - Nifra vs the meta-frameworks

One section per UI framework, each with two explicitly-labelled tables: A - dynamic SSR (the page rendered on every request, no caching) and B - cacheable (the same page from each framework's SSG/ISR mode). Meta-frameworks run on Node through their own production server. Nifra shows Bun and Node rows (@nifrajs/node) so the Node rows compare apples-to-apples. The headline multipliers below are Table A only.

25×Nifra + React vs Next.js (Node)
Nifra + Solid vs SolidStart (Node)
Nifra + Vue vs Nuxt (Node)
Nifra + Svelte vs SvelteKit (Node)

React

A - Dynamic SSR. The page is rendered on every request, no caching: the per-request cost, the number that matters for pages that can't be cached.

Targetreq/sp50p99client JS (gz)
Nifra + React (Bun)33,8341.40 ms2.77 ms59.8 KB
Nifra + React (Node)28,0431.73 ms3.43 ms59.8 KB
Next.js (Node)1,11544.36 ms56.98 ms182.4 KB
Remix (Node)2,10323.72 ms31.53 ms95.4 KB

B - Cacheable. The same page served from each framework's cached mode - SSG, and ISR where supported (cache warmed before measuring). A cached row is not an SSR row: compare within this table only.

Targetreq/sp50p99client JS (gz)
Nifra + React SSG (Bun)36,7661.29 ms2.58 ms70.7 KB
Next.js static (Node)6,7097.21 ms12.07 ms182.4 KB
Nifra + React ISR (Bun)104,2910.43 ms0.96 ms70.7 KB
Next.js ISR (Node)6,6127.34 ms12.33 ms182.4 KB

Solid

A - Dynamic SSR. The page is rendered on every request, no caching: the per-request cost, the number that matters for pages that can't be cached.

Targetreq/sp50p99client JS (gz)
Nifra + Solid (Bun)34,9651.35 ms2.64 ms6.3 KB
Nifra + Solid (Node)29,6111.60 ms3.21 ms6.3 KB
SolidStart (Node)7,3725.62 ms16.26 ms18.8 KB

B - Cacheable. The same page served from each framework's cached mode - SSG, and ISR where supported (cache warmed before measuring). A cached row is not an SSR row: compare within this table only.

Targetreq/sp50p99client JS (gz)
Nifra + Solid SSG (Bun)36,7491.29 ms2.58 ms12 KB
SolidStart static (Node)19,2182.45 ms4.32 ms18.3 KB

Vue

A - Dynamic SSR. The page is rendered on every request, no caching: the per-request cost, the number that matters for pages that can't be cached.

Targetreq/sp50p99client JS (gz)
Nifra + Vue (Bun)27,7921.70 ms3.38 ms27 KB
Nifra + Vue (Node)19,6602.35 ms4.69 ms27 KB
Nuxt (Node)2,82815.88 ms43.60 ms72.2 KB

B - Cacheable. The same page served from each framework's cached mode - SSG, and ISR where supported (cache warmed before measuring). A cached row is not an SSR row: compare within this table only.

Targetreq/sp50p99client JS (gz)
Nifra + Vue SSG (Bun)37,0811.28 ms2.55 ms12 KB
Nuxt static (Node)20,2882.38 ms3.42 ms65.5 KB

Svelte

A - Dynamic SSR. The page is rendered on every request, no caching: the per-request cost, the number that matters for pages that can't be cached.

Targetreq/sp50p99client JS (gz)
Nifra + Svelte (Bun)45,6851.04 ms2.07 ms21.2 KB
Nifra + Svelte (Node)30,2611.48 ms3.32 ms21.2 KB
SvelteKit (Node)7,6436.09 ms12.57 msn/a

B - Cacheable. The same page served from each framework's cached mode - SSG, and ISR where supported (cache warmed before measuring). A cached row is not an SSR row: compare within this table only.

Targetreq/sp50p99client JS (gz)
Nifra + Svelte SSG (Bun)36,9931.28 ms2.56 ms19.5 KB
SvelteKit static (Node)24,8711.76 ms4.09 ms30.1 KB

Preact

A - Dynamic SSR. The page is rendered on every request, no caching: the per-request cost, the number that matters for pages that can't be cached.

Targetreq/sp50p99client JS (gz)
Nifra + Preact (Bun)34,1401.40 ms2.77 ms7.7 KB
Nifra + Preact (Node)29,5031.64 ms3.27 ms7.7 KB
Raw Preact render (Node, ceiling)35,7171.36 ms2.69 ms4.6 KB

B - Cacheable. The same page served from each framework's cached mode - SSG, and ISR where supported (cache warmed before measuring). A cached row is not an SSR row: compare within this table only.

Targetreq/sp50p99client JS (gz)
Nifra + Preact SSG (Bun)36,7801.29 ms2.57 ms15.4 KB
Meta-frameworks are Node-only in this matrix; compare them against Nifra's Node row (the headline multipliers above do exactly that). Preact has no maintained meta-framework, so its section is Nifra-only - Bun vs Node on the same app. A client-JS of n/a means the run couldn't account that framework's payload from the SSR HTML.

Backend - HTTP throughput across runtimes

Nifra is also a standalone API framework. Two core workloads - a path-param GET and a validated POST - each runtime through Nifra's real adapter, next to that runtime's raw handler and the popular libraries. Rows are ordered by the geometric mean of the workloads, so no single column decides the ranking.

Bun

FrameworkGET /users/:idPOST /users
bun-native149,462130,810
Nifra150,956119,363
Elysia151,931117,652
Hono127,00993,525

Node

FrameworkGET /users/:idPOST /users
Nifra92,12072,661
node-raw86,79674,085
Fastify71,58956,685
Elysia77,65449,764
Express51,79643,320
Hono52,25535,424

Deno

FrameworkGET /users/:idPOST /users
deno-raw147,618140,889
Nifra141,713117,773
Elysia147,89598,689
Hono131,425102,609

Backend - the same routes with a real route's work

The tables above are the shape every framework publishes: a bare route doing nothing but routing. This is the same GET and POST after the route gains what an actual API route has - security headers, CORS, a request-id hook, bearer auth through a derive, and a cookie read. That combination disqualifies the route from every one of Nifra's fused fast lanes, so these are the pessimistic numbers, not the flattering ones. The third column adds one body-observing middleware to the same GET.

Bun

FrameworkGET /api/ordersPOST /api/ordersGET + body hash
bun-native89,64396,16768,540
Nifra85,40182,45165,129
Elysia85,27082,98957,081
Hono49,61751,28033,503

Node

FrameworkGET /api/ordersPOST /api/ordersGET + body hash
node-raw61,18263,01854,882
Nifra62,12356,20356,066
Fastify62,55651,06157,950
Elysia50,07539,76235,161
Express39,54137,27638,366
Hono26,61022,87419,304

Deno

FrameworkGET /api/ordersPOST /api/ordersGET + body hash
deno-raw67,59785,96958,846
Nifra62,63472,87655,200
Elysia56,37661,10641,913
Hono31,76135,03913,384

Reproduce locally with bun run bench:http:update, bun run bench:http:realworld:update, and bun run bench:ssr. Same-run ratios matter more than absolute req/s.