DEV Community

bunzzeok
bunzzeok

Posted on

I Built the Same Commerce App in Kudzu, Astro, React Router, TanStack Start, and Next.js

In my previous post, I introduced Kudzu, a compiler-first framework that turns a statically analyzable subset of React-shaped TSX into static HTML and route-specific JavaScript without shipping React, a virtual DOM, or a hydration runtime.

That raises an obvious question:

What happens when you move beyond counters and small demos?

So I built the same commerce application five times:

  • Kudzu
  • Astro + React islands
  • React Router
  • TanStack Start
  • Next.js App Router

The goal wasn't to create a synthetic benchmark where Kudzu could win.

I wanted to replay something closer to an actual user session and measure what the browser experiences.

The benchmark is open source:

https://github.com/SimYunSup/kudzu-based-bench

The fixture

Each implementation represents the same store with the same behavioral contract.

There are six routes covering:

  • home
  • search with filtering and sorting
  • collections
  • product details
  • policy/content
  • checkout

The interactive paths include product options, adding items to the cart, filtering, sorting, navigation into product pages, back navigation, and cart state.

All five versions emit complete HTML.

That matters because simply measuring when text becomes visible doesn't tell us much here.

The more interesting question is:

When does the page become reliably interactive, and what did the browser have to download to get there?

Why I didn't make this an LCP benchmark

LCP is useful, but it doesn't distinguish these implementations particularly well in this fixture.

The LCP element is generally a product image, and the image bytes are intentionally identical between implementations.

A framework benchmark where the dominant measurement is an identical image mostly tells us about the image.

Instead, I focused on observable application behavior:

  • contentReady: when the important content exists in the DOM
  • actReady: when a control actually works
  • stepLatency: successful interaction to next paint
  • navigation latency
  • dropped early clicks
  • bytes transferred across the session
  • JavaScript downloaded per route
  • behavior when JavaScript is delayed or partially unavailable

The browser is the judge.

I don't use framework-internal "hydration complete" signals.

Replaying an actual session

The main test runs under:

Slow 4G + 4× CPU slowdown

and replays the same interactions five times for each implementation.

The median results for initial listing interactivity were:

Framework contentReady actReady
Kudzu 170 ms 250 ms
Astro 223 ms 2,229 ms
TanStack Start 170 ms 2,859 ms
React Router 170 ms 2,957 ms
Next.js 178 ms 3,537 ms

The content itself appears at roughly the same time.

That's expected: every implementation ships complete HTML.

The large difference appears between seeing the interface and being able to reliably use it.

For Kudzu, the compiler-generated behavior is available after roughly 250 ms in this test.

For the React-based implementations, more client-side machinery has to arrive and execute first.

How much JavaScript reaches each route?

I also measured JavaScript from the browser's network activity rather than statically crawling the import graph.

That distinction turned out to matter.

For example, Astro can load island runtime code through dynamic imports that a naive static crawler can miss.

Here are the initial route-level JavaScript totals, gzip compressed:

Framework Home Search Product Checkout
Kudzu 4.7 KB 9.4 KB 4.9 KB 4.7 KB
Astro 60.6 KB 61.0 KB 61.1 KB 60.6 KB
TanStack Start 101.7 KB 101.7 KB 101.9 KB 101.3 KB
React Router 104.3 KB 104.2 KB 104.4 KB 103.9 KB
Next.js 134.2 KB 134.8 KB 133.8 KB 132.8 KB

This is the architectural difference I wanted to investigate when I started Kudzu.

Kudzu's search route needs keyed-list behavior, so it ships more JavaScript than the simpler routes.

The other routes don't pay for that capability.

The generated JavaScript follows what the route actually uses.

But SPA navigation wins somewhere else

I didn't want the benchmark to stop at initial page load.

The session opens a product using a real link, adds it to the cart, and then navigates back.

For listing → product navigation:

Framework Navigation
TanStack Start 182 ms
React Router 185 ms
Astro 222 ms
Kudzu 271 ms
Next.js 360 ms

Here the SPA routers show a real advantage.

React Router and TanStack Start perform the transition faster than Kudzu's document navigation.

That's an important tradeoff.

Removing a persistent application runtime doesn't magically make every operation faster.

It changes where the costs occur.

What happens across the whole session?

I also measured all network transfer across the session, including prefetching.

Script transfer was:

Framework Script transferred
Kudzu 34.4 KB
Astro 193.1 KB
TanStack Start 317.6 KB
React Router 322.3 KB
Next.js 455.5 KB

This is more interesting to me than a single initial bundle number.

Users don't experience isolated benchmark pages.

They enter an application, navigate, interact, reuse cached resources, and sometimes download things speculatively prefetched by the framework.

So the session should carry its cache forward too.

What if JavaScript arrives late?

I also wanted to test something performance benchmarks often ignore:

failure and degradation.

I tested six capabilities:

  1. reading content
  2. category navigation
  3. entering a product
  4. filtering
  5. selecting an option
  6. adding to cart

under three conditions:

  • JavaScript completely blocked
  • scripts delayed by two seconds
  • one script request lost

That gives 18 capability checks per implementation.

Results:

Framework Surviving capabilities
Kudzu 15 / 18
Astro 12 / 18
TanStack Start 8 / 18
React Router 8 / 18
Next.js 8 / 18

None of them magically retain full interactivity without JavaScript.

But their failure modes are different.

That's something I want to explore much more deeply.

Kudzu also has a scaling problem

One result I don't want to hide is build scaling.

With 1,000 catalog items, median build times were approximately:

Framework Build time
Astro 1.82 s
TanStack Start 2.47 s
React Router 3.07 s
Kudzu 3.56 s
Next.js 5.62 s

More importantly, Kudzu currently has the steepest scaling curve between 100 and 1,000 products.

That's a compiler architecture problem.

Kudzu currently emits capability modules per product in places where that work should be shared or amortized more effectively.

So while the runtime results are encouraging, I wouldn't call this proof that Kudzu scales to large applications.

It doesn't yet.

What I learned

The biggest takeaway for me isn't simply that "less JavaScript is faster."

That's too simplistic.

The more interesting result is that different architectures move cost to different places.

A compiler-first architecture can dramatically reduce the amount of framework machinery required in the browser.

But SPA routers can provide faster client-side navigation.

Compiler specialization can reduce route JavaScript.

But generating specialized artifacts can increase build cost as the application grows.

Avoiding hydration can make interactions available earlier under constrained networks.

But that doesn't automatically solve application architecture, state management, forms, routing, or ecosystem compatibility.

Those are the problems I'm working on next.

This still isn't a large-app benchmark

The commerce fixture is intentionally much larger than a toy benchmark, but I don't consider it evidence that Kudzu is ready for a truly large production application.

The next step is larger fixtures with:

  • shared state
  • async/server state
  • deeper component and module graphs
  • forms
  • authentication
  • more complex routing
  • broader React ecosystem integration

In fact, I've already started using separate form and documentation/search fixtures because the commerce benchmark doesn't expose every architectural weakness.

Some of those tests make Kudzu look much less flattering.

That's useful.

A benchmark should tell me where the architecture breaks, not just give me a chart I can put on a landing page.

If you're interested in compiler-first frontend architecture, I'd especially like feedback on the benchmark methodology and what kinds of real application behavior I should test next.

Benchmark repo:
https://github.com/SimYunSup/kudzu-based-bench

Kudzu:
https://github.com/kudzujs/kudzu

Top comments (0)