Skip to content

It's all about speed

Modern frameworks made one promise: performance and a better developer experience. They broke it — and then explained the failure with vocabulary designed to keep you from noticing. React failed. Next failed.

The fix isn’t a cleverer abstraction. It’s an honest definition of what “fast” even means, and a runtime that does the few things that definition demands.

“Hydration” is the word the industry reaches for to name the moment a page you were shown becomes a page you can use. It’s a terrible word — vague, faintly mystical, and it lets a framework bury seconds of main-thread work behind a noun nobody questions.

Why is it called that at all? Two reasons — one a metaphor, one a real historical cost.

The metaphor. Server HTML was cast as “dry” — static, lifeless — and the client JS as “water” you pour on to make it “come alive.” Hence re-hydrate. It’s a sticky image, but it’s misleading twice over: the HTML isn’t dry — it’s complete and already painted (you can see and read it); and “just add water” makes it sound effortless, which hides what it actually cost in the frameworks that coined it.

The real cost — this is why the name was earned there. In React/Vue/Ember-era SSR, hydration genuinely was a separate, heavyweight phase, and not an update:

  • The framework re-ran the entire component tree on the client, building a fresh virtual DOM.
  • It then reconciled that VDOM against the server’s HTML to “claim” the nodes (naive versions historically threw the HTML away and rebuilt).
  • It was a distinct code path, with its own cost (re-render the whole app before anything’s interactive), its own failure class (“hydration mismatch” warnings), its own mental model.

In that world, “hydration” named something real and distinct from an update — so it deserved its own noun. The cost was large enough that it felt like a phase you waited through.

Phaze collapses that phase out of existence. No VDOM to rebuild, no tree to diff, no reconciliation. What’s left is the binding system’s first tick, adopting the DOM that’s already there — the page is live the moment those bindings wire up. The grand noun is no longer earned: calling it “hydration” in Phaze is a historical hand-me-down for the first update. The industry’s heaviest SSR concept turns out, in a truly-reactive runtime, to be the cheapest thing — an update that happens to reuse the DOM that’s already there.

While we’re naming things honestly: reconciliation. It sounds like a feature. It’s an admission — “we added an extra step because the framework can’t tell what changed, so it rebuilds the tree and compares it to the old one to find out.”

Phaze has none of that. There’s nothing to reconcile because nothing was thrown away and rebuilt. A truly reactive runtime knows what needs to update — the exact binding that reads the changed signal — and updates only that. That’s the most performant thing you can do with compute: no rebuild, no diff, no comparing the new tree to the old to rediscover what you already knew.

Getting the page in front of you and alive is the one thing you can’t define away — so Phaze does it the quickest way possible, in the two places that decide the scorecard above.

How quickly you see it — the server generates the HTML

Section titled “How quickly you see it — the server generates the HTML”

“Server-side rendering” is a misleading legacy name: nothing is rendered on the server. Rendering — markup into pixels — only ever happens in the browser. What the server does is generate an HTML string: it runs your components and serializes the resulting DOM tree to text. The browser is what renders it. (We’ll keep saying “SSR” — it’s the term everyone knows — but generation is what it is.)

So the browser’s engine parses that HTML into a DOM and paints it before a single byte of Phaze JavaScript runs. Phaze’s runtime isn’t in the see-it path at all. What makes you see it fast is that the server shipped complete, real HTML — the browser can paint without waiting on JS to build the page. (A client-rendered SPA ships blank HTML → download + run a big bundle → build the DOM → then paint; there, bundle size directly delays first paint. SSR breaks that coupling.)

And because Phaze’s runtime is so small, it rides in on the same round trip as the HTML — about one packet, in hand by the time the DOM is painted. You get it for free.

How quickly you can use it — the smallest reactive runtime

Section titled “How quickly you can use it — the smallest reactive runtime”

The painted page is inert until the runtime wires behavior onto it — and that is the runtime’s only job. Phaze’s is the smallest reactive runtime there is, sub-3 KB brotli (next to every other reactive framework): about one packet to download, sub-millisecond to parse.

And what it does is cheap, because the expensive half is already done. A client-rendered framework spends JS twice — first to construct the DOM (every node), then to wire behavior onto it. With SSR the browser already constructed the tree, natively, for free, while the bytes streamed in. So Phaze skips construction entirely and does only the second half: walk the existing tree and attach listeners + reactive bindings. Adopt, not rebuild — which is why hydration is just an update, and why “usable” lands right behind “visible.”

And it ships from the server closest to you. Phaze on Cloudflare runs that SSR at the edge, so “how quickly you see it” isn’t bottlenecked by a round trip to one origin halfway around the world.

You don’t opt out of SSR for interactivity

Section titled “You don’t opt out of SSR for interactivity”

Every React/Next developer carries the same instinct: anything interactive has to be a client component. Tilt, drag, animation, live validation, a sensor-driven 3D scene — reach for "use client", ship it client-only, give up the server-rendered HTML. That instinct is a scar from a model where hydration was a heavyweight re-render, so “interactive” came to mean “opt out of SSR.”

In Phaze it’s a false choice. Interactivity is just behavior — event handlers, animations, sensor wiring — attached to elements. SSR produces the HTML; hydration, which is just an update, attaches the behavior to that exact HTML. “Server-rendered” and “interactive” are orthogonal axes: the content renders on the server, the behavior wires up on the client, and you keep both.

We put this to the test with about as rich as client interactivity gets — a device-orientation- and pointer-driven 3D tilt with live CSS perspective, SVG line-draw animations, and 3D-preserving view-transition page navigations (built with graviton, a Phaze motion library). Every bit of it is server-rendered: the headline, the logo, the marks are in the HTML — indexable, painted before any JS runs — while the tilt and the animations wire up on hydrate. No ssr={false}, no SSR surrendered, no flash.

So when do you opt out? Only when a component literally cannot run on the server — a WebGPU canvas needs a real GPU context, geolocation needs a browser API. ssr={false} means “this can’t execute server-side,” not “this is interactive.” That set is tiny. Everything else — every animation, gesture, form, transition — server-renders and comes alive on the update.

Two different wins, powered by two different things:

  • See it fast — keep JS off the critical path entirely (SSR ships paint-ready HTML). Runtime size is irrelevant here.
  • Use it fast — make the JS that does run tiny (≈one packet, sub-ms parse), and what it does cheap (adopt the existing DOM, don’t rebuild it).
the questionPhaze’s answer
What do you see?real, server-generated HTML
How quickly do you see it?complete HTML, painted by the browser, from the edge
How quickly can you use it?a sub-3 KB runtime that adopts the DOM — “hydration” is just an update

That’s the whole thing. No magic, no invented vocabulary. The app gets to you quicker. Period.