DEV Community

bunzzeok
bunzzeok

Posted on

Can a Compiler-First Framework Scale to Real Apps Without Reinventing React?

A few weeks ago, I wrote about Kudzu, an open-source compiler-first web framework that lets you write familiar React-shaped TypeScript/TSX without shipping React, a VDOM, or hydration by default.

The original idea is straightforward:

  • write familiar TSX
  • analyze components, state, events, lists, effects, and dependencies at build time
  • emit complete HTML
  • ship only the JavaScript capabilities a page actually needs

That part works.

But I think the more interesting problem starts after that.

Static pages were never the hard part

A compiler can make a static page extremely small.

That does not automatically make it a serious application framework.

The real question is:

Can Kudzu grow into something capable of building large, long-lived applications without eventually recreating the same generic runtime model it was designed to remove?

By “real applications,” I mean things like:

  • shared application state
  • async/server data
  • loading and error states
  • cache invalidation
  • optimistic mutations
  • complex forms
  • nested routing
  • authentication and permissions
  • realtime updates
  • large lists and virtualization
  • editors
  • charts and maps
  • code splitting
  • long-lived application state

If Kudzu cannot handle those well, then it risks ending up as a very good static-site compiler with some interactivity.

That is not the goal.

The goal is not zero JavaScript

This distinction matters.

I do not think a serious web application should avoid client-side JavaScript at all costs.

A dashboard may genuinely need:

  • shared state
  • navigation
  • server data
  • caching

A chat application may genuinely need:

  • WebSocket connections
  • keyed lists
  • lifecycle management
  • optimistic updates

An editor may need a substantial JavaScript library.

That is fine.

The goal is not:

zero JavaScript

The goal is closer to:

zero JavaScript that exists only because the framework needs it

A static route might ship almost nothing.

A complex application route might ship much more.

But that code should correspond to capabilities the application actually uses.

Where I do not want Kudzu to go

There are two easy ways to make compatibility grow quickly.

I think both are dangerous.

1. Rebuild React underneath Kudzu

The simplest escape hatch would be to add:

  • a generic component tree
  • VDOM reconciliation
  • hydration
  • a generic rerender loop
  • a React-compatible fallback runtime

That would make more React code easier to support.

But it would also erase much of the reason Kudzu exists.

The architecture I want to preserve is closer to:

state change
    ↓
known dependency
    ↓
specific DOM / resource / list update
Enter fullscreen mode Exit fullscreen mode

instead of:

state change
    ↓
component rerender
    ↓
virtual tree
    ↓
diff
    ↓
DOM update
Enter fullscreen mode Exit fullscreen mode

2. Add endless compiler special cases

The other failure mode is less obvious.

It looks like this:

React Router special case
→ Zustand special case
→ TanStack Query special case
→ React Hook Form special case
→ MUI special case
→ browser API special case
→ ...
Enter fullscreen mode Exit fullscreen mode

That may work for a while.

But eventually the compiler becomes a catalog of package-specific syntax patterns.

Then users are no longer writing normal React-shaped code.

They are writing:

“the specific shape Kudzu happens to understand”

That is also a problem, especially for AI-assisted development.

If an AI agent constantly has to read compiler limitations, rewrite source into special forms, retry builds, and search framework docs, the token savings disappear.

The direction I am exploring

The architecture I am currently leaning toward has three layers.

React / npm ecosystem source
            ↓
compatibility / normalization
            ↓
small Kudzu application model
            ↓
compiler
            ↓
HTML + only required runtime capabilities
Enter fullscreen mode Exit fullscreen mode

The important part is the middle.

Kudzu needs a small set of application capabilities that are powerful enough to build serious applications.

Not hundreds of framework-specific features.

Something closer to:

  • local state
  • shared state
  • derived values
  • events
  • async resources
  • mutations
  • navigation
  • keyed/owned DOM ranges
  • lifecycle
  • external UI instances
  • lazy capabilities

The exact list is still something I am working through.

The goal is that a small number of primitives can be composed into many different applications.

What about third-party libraries?

I do not think Kudzu should try to compile the internals of every library.

Some packages should simply run normally.

For example:

  • Zod
  • date-fns
  • Dexie
  • Three.js
  • MapLibre

If a library already owns a canvas, WebGL context, or DOM subtree, Kudzu may only need to manage:

mount
update
dispose
lifetime
Enter fullscreen mode Exit fullscreen mode

For example:

Kudzu
  └─ map container
       └─ MapLibre owns the internals
Enter fullscreen mode Exit fullscreen mode

No VDOM is required for that.

The same idea may work for:

  • CodeMirror
  • Monaco
  • ProseMirror
  • Chart.js
  • ECharts
  • data grids
  • media players

This is very different from embedding a React island.

Kudzu would not try to recreate the package's internal rendering model.

It would only own the boundary.

React ecosystem compatibility still matters

I do want practical React migration compatibility.

But I think there is an important distinction between:

React runtime compatibility

and:

React source compatibility

The long-term goal is closer to:

maximize React ecosystem source compatibility while minimizing React runtime compatibility

That means different packages may need different strategies.

Native

Normal JavaScript/TypeScript packages can run as-is.

Compiled

Some familiar React-shaped patterns can be understood and compiled away.

Normalized

Some source can be transformed into simpler HTML/JavaScript/Web API code before it reaches the core compiler.

For example:

<Link to="/users">Users</Link>
Enter fullscreen mode Exit fullscreen mode

could conceptually become:

<a href="/users">Users</a>
Enter fullscreen mode Exit fullscreen mode

Adapter

Some libraries may need package-specific migration logic.

External owned UI

Some complex UI libraries can own a bounded DOM/canvas area.

Partial or unsupported

Some React libraries may rely deeply on React reconciliation or component-tree semantics.

I think it is better to explicitly say “unsupported” than silently fall back to a React runtime.

Performance so far

There are two sets of performance evidence I have been using.

The public cross-framework benchmark currently uses an earlier Kudzu version, so I do not treat it as a current-version benchmark.

Still, it is useful for understanding the architecture.

On a commerce fixture under Slow 4G + 4× CPU throttling, the published results included:

  • Kudzu first interactive listing: 450ms
  • Astro: 2.22s
  • TanStack Start: 2.90s
  • React Router: 2.96s
  • Next.js App Router: 3.54s

Kudzu did not win everything.

The 3-step form benchmark exposed a clear weakness in cross-page state propagation:

  • TanStack: 191ms
  • Astro: 196ms
  • React Router: 395ms
  • Next.js: 365ms
  • Kudzu: 700ms

I think that loss is useful.

It shows exactly the kind of application-level problem that matters more than shaving another few hundred bytes off a bundle.

Kudzu's own maintained performance evidence also showed a stateful capability bundle substantially smaller than React/Vue/Svelte in that specific fixture, and large generated-route builds scaling competitively into the thousands of routes.

I do not consider any of those numbers universal proof.

They are fixture-specific.

The part I care about most now is whether those characteristics survive as application complexity increases.

The next test should not be another blog

I think the next serious test for Kudzu needs to be an actual application.

Something like a small Linear / GitHub Issues / Jira-style app with:

  • login
  • workspaces
  • shared state
  • nested routing
  • server data
  • loading/error states
  • caching
  • mutations
  • optimistic updates
  • forms
  • modals
  • search/filtering
  • realtime updates
  • a large list
  • lazy-loaded editor or chart

The goal is not to build another demo that happens to match the compiler.

The goal is to let the application expose where the compiler model is insufficient.

Then:

application fails
↓
identify the general missing capability
↓
check whether existing primitives can express it
↓
only add a new primitive if the limitation repeats across multiple real apps
Enter fullscreen mode Exit fullscreen mode

That is the development loop I want to follow.

AI development is part of the design

There is another reason I care about keeping the application model small.

AI coding agents already understand React-shaped TypeScript/TSX extremely well.

I do not want Kudzu to replace that with an entirely new DSL or dozens of Kudzu-specific APIs.

Ideally an AI should be able to write familiar code while the compiler handles things the model should not need to reason about repeatedly.

That includes things like:

  • dependency tracking
  • unnecessary rerender semantics
  • framework boilerplate
  • some migration transformations
  • precise diagnostics

The metric I eventually want to measure is not just bundle size.

It is:

cost per successful task

For the same feature, using the same coding agent:

  • how many tokens were used?
  • how many files were opened?
  • how many build attempts?
  • how many compiler failures?
  • how many edits?
  • how much framework documentation had to be read?
  • did the final application actually behave the same?

If Kudzu uses less client JavaScript but makes the AI fight the compiler for twice as long, that is not a win.

Where Kudzu is now

Kudzu is still experimental.

The current work is moving increasingly toward application-level behavior rather than only static output.

But I do not think the large-application question is solved yet.

That is the part I am trying to figure out now.

The two constraints I am trying to hold at the same time are:

1. Do not rebuild React underneath the compiler.

2. Do not let “minimal runtime” prevent Kudzu from becoming a real application framework.

I think the interesting architecture is somewhere between those two extremes.

Project:

https://kudzujs.cloud

GitHub:

https://github.com/kudzujs/kudzu

Public benchmark:

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

I'd be interested in hearing from people who have worked on large React, Vue, Svelte, Solid, or similar applications:

What browser-side capabilities do you consider genuinely unavoidable for serious web applications?

And which ones do you think mostly exist because of the rendering model of the framework you are using?

Top comments (0)