The Real Battle in UI Design Is Not Speed, It Is What You Choose Not to Wake Up

Jaeyeol Lee

Hatched by Jaeyeol Lee

Apr 18, 2026

11 min read

87%

0

The hidden question behind every modern framework

What if the biggest performance problem in web development is not that the framework does too little, but that it does too much at the wrong time?

That question cuts deeper than the usual debate about rendering speed, bundle size, or API ergonomics. Beneath the surface, modern frontend frameworks are all wrestling with the same thing: how to know exactly when work must happen, and how to avoid work that only feels necessary because we are used to doing everything eagerly.

Once you look at the problem that way, the familiar categories start to look less like competing religions and more like different answers to a single scheduling problem. Some frameworks wake up broadly and often. Some wake up narrowly. Some try to predict what will matter. Some refuse to wake anything until absolutely needed. The real tension is not simply reactivity versus non reactivity. It is how much of the system should be asleep by default.

That framing matters because most of the cost in user interfaces is hidden not in the visible update, but in the invisible preparation around it. A counter increments. A label changes. But behind that tiny change, a whole chain of work may unfold: rerendering components, re executing functions, reconnecting data, rebuilding state, or replaying startup logic. The user sees one number go from 1 to 2. The browser may do far more than that.


Coarse wakeups, fine wakeups, and the price of being vague

A useful way to understand reactivity is to ask a blunt question: when one value changes, how much of the application has to guess what might be affected?

In coarse grained systems, the answer is often: a lot. If something changed, rerun a component, rerun the tree, rerun enough of the surrounding structure to be safe. This is not irrational. It is simple, conceptually clean, and often good enough. But it comes with a hidden tax: the framework is doing extra work because it does not know exactly what depends on what.

Fine grained systems attack that uncertainty directly. Instead of saying, “Something changed, let us inspect everything,” they say, “This exact value changed, and only the exact dependents need attention.” That shift sounds small, but it changes the entire shape of the system. It is the difference between checking every room in a building when one light turns on and walking straight to the switch panel connected to that one bulb.

This is where signals become powerful. A signal is not just a value. It is a value with bookkeeping. It acts like a traffic cop for dependencies. When code reads a signal, the system records that the read happened. Later, when the signal changes, the framework knows exactly who was listening. The read created the map. The update follows the map.

A reactive system is only as smart as its dependency bookkeeping.

This is the real leap. Reactivity is not magic. It is accounting. The framework is constantly maintaining a ledger of who touched what, so that when something changes, it can avoid waking the whole city.

That is why fine grained systems can feel so elegant. They do less work because they know more. Coarse grained systems do more work because they know less. The tradeoff is not merely technical, it is philosophical. Do you want the framework to infer broad intent, or do you want it to track precise dependency edges?

Consider a simple counter display with an increment button and a wrapper component. In a coarse system, a state change may rerender the counter, the wrapper, and other surrounding pieces, even if only the visible value changed. In a fine grained system, the update can stop at the exact text node that needs the new number. The increment button does not need to be reevaluated. The wrapper does not need to be reentered. The framework has enough information to say, “Do not descend any further.”

That phrase matters. Do not descend any further is the essence of efficient reactivity. Most frameworks try to be smart after the fact. Fine grained systems try to prevent unnecessary descent in the first place.


The deeper shift: from rerendering to remembering

The conventional conversation about frontend performance often assumes the main challenge is rendering. But rendering is only half the story. The other half is memory, not in the hardware sense, but in the architectural sense: what does the system remember about the path that led to the current state?

This is where the contrast between hydration and resumability becomes especially revealing. Hydration assumes the browser receives a pre rendered application and then must reanimate it on the client. In practice, that means a large amount of the app has to be loaded, reconstructed, and reattached before it becomes interactive. The page may look ready, but the runtime still has to wake up and relearn its own shape.

Resumability takes a radically different stance. Instead of replaying the story from the beginning, it pauses on the server and resumes on the client. The point is not merely that less code runs. The point is that the runtime does not need to rediscover what it already knew. It carries forward the execution state, so interactivity begins where computation left off.

That is a profound inversion. Hydration says: rebuild the living system from static output. Resumability says: preserve the living system across environments.

The analogy that best captures this difference is a theater performance. Hydration is like filming the play, then asking the audience to reconstruct the staging from the recording before the next act begins. Resumability is like freezing the play mid scene, moving the actors to another stage, and continuing exactly where they left off. One method requires reconstruction. The other requires continuity.

This is also why the distinction between what is structural and what is merely value changing matters so much. If a component only needs a new number or text, why should the entire component need to be downloaded or replayed? If the DOM structure does not change, why wake the logic that only exists to create that structure?

The answer is often habit. We have built many systems around the assumption that a user interface must be fully reconstituted before it can breathe again. Resumability challenges that habit by insisting that interactivity can be preserved more selectively.

The most expensive code is not always the code that runs. It is the code that must be remembered, reloaded, or replayed just to prove it does not need to run.

That is the hidden cost of coarse thinking. We spend enormous effort on proving safety by over executing. Fine grained reactivity and resumability are both strategies for reducing that proof burden.


A mental model: the system is a city, not a stage

To connect these ideas, it helps to replace the old mental model of a UI as a static stage with a new one: a city with many districts, roads, and local rules.

In a stage model, every change risks reconfiguring the whole set. Lights, props, actors, and cues are tightly coupled. If one thing shifts, the safest move is to reconsider everything. That resembles coarse rerendering. It is orderly, but blunt.

In a city model, by contrast, each district has local state, local traffic patterns, and local dependencies. A change in one neighborhood should not force the subway system to rebuild itself. Signals are like traffic sensors that tell the city exactly where movement occurred. Fine grained reactivity makes the city responsive without turning every street into a bottleneck.

Resumability adds another layer. It is not only about local traffic. It is about keeping the city alive across time without rebuilding it every morning. The city does not need to reconstruct its road map from scratch when the sun rises. It resumes operations from the state it had when the lights went out.

This model clarifies why different frameworks can feel so different even when they all claim to be reactive. Some use subscriptions, some use compiler analysis, some use signals, some use refs, some rely on compilation to figure out what changed, and some push the architecture further by avoiding hydration altogether. These are not just implementation details. They are different answers to the same urban planning question: how much central coordination should be required to keep local life moving?

A subscription system says: tell me when something changes, and I will notify the interested parties. A signal system says: I already know who cared because I recorded the read. A compiler based system says: I will analyze your code ahead of time and reduce the runtime’s uncertainty. A resumable system says: I will preserve enough context that the client does not need to reconstruct the past.

Each approach reduces work in a different place. Subscriptions reduce polling. Signals reduce rerender breadth. Compilers reduce runtime guessing. Resumability reduces startup reconstruction. They are all optimization strategies, but they optimize different forms of ignorance.

That last phrase may be the most useful lens of all: different forms of ignorance. A framework can be ignorant about who depends on a value, or about what changed in a component, or about how much of the app must be restored, or about which code even needs to ship. The best architectures are those that remove ignorance at the lowest possible cost.


The real design principle: do not wake what does not need to dream

If there is one thesis that emerges from all of this, it is simple:

The future of frontend architecture is not just about making updates faster. It is about making unnecessary wakeups impossible.

That sounds like an optimization slogan, but it is actually a design principle. Every time a framework makes something reactive, it is also deciding what kind of sleep the system is allowed to have. Can components stay dormant until truly needed? Can the framework know which reads matter? Can the browser receive just enough information to continue rather than recreate? Can the runtime avoid re executing logic that has no structural consequence?

These questions matter because application complexity does not grow linearly. As UIs become more interactive, more data driven, and more personalized, the cost of waking everything becomes increasingly wasteful. The bottleneck is not only CPU cycles. It is developer cognition. Broad rerendering hides causality. Fine grained systems expose it. Resumable systems preserve it.

This is why the most important advantage of fine grained reactivity is not raw speed, though speed is real. It is locality of reasoning. When a signal updates, you can reason about exactly what changed. When a component does not rerender, you learn something important about the boundary of responsibility. When a system resumes rather than hydrates, you understand that the runtime has been designed to carry state across the network boundary without pretending the boundary does not exist.

A mature frontend system should not make every change feel global. It should let changes remain local unless they truly alter structure. If a value changes, update the value. If structure changes, then yes, wake the component. But do not pay the cost of a structural recalculation for a textual update.

That distinction sounds obvious, yet many systems blur it. They treat data changes as if they might be structure changes, or structure changes as if they might require total reanimation. Better systems are more disciplined. They ask: what is actually affected, and what merely feels adjacent?

This is where the field may be heading: not toward one universal framework, but toward a shared architectural ethic. The ethic says that a user interface should reveal the minimum amount of work necessary to preserve correctness. Everything else should stay asleep.


Key Takeaways

  1. Separate value changes from structural changes. Not every update should trigger the same amount of work. If the DOM shape does not change, avoid reexecuting logic that only exists to create that shape.

  2. Track dependencies precisely, not vaguely. Signals and similar mechanisms work because they record reads. That lets the system update only the exact dependents later.

  3. Prefer continuity over reconstruction when possible. Resumability is powerful because it preserves execution state instead of rebuilding it after the fact.

  4. Ask what your framework is waking up. A good performance question is not just “How fast is the update?” but “How much of the app had to wake up for this update?”

  5. Design for locality of reasoning. The best reactivity systems make cause and effect easier to see. That helps both the runtime and the humans maintaining it.


Conclusion: the smartest system is the one that knows when to stay asleep

The intuitive story about frontend progress says that better frameworks render faster. That is true, but incomplete. The deeper story is that better frameworks become more selective about consciousness itself. They know what to notice, what to record, what to replay, and what to leave untouched.

In that sense, the real competition is not between Reactivity A and Reactivity B. It is between two philosophies of computation. One philosophy says, when in doubt, wake more of the system. The other says, when in doubt, preserve locality and avoid wakeups. One builds around rerendering and reconstruction. The other builds around dependency precision and continuity.

The most interesting shift is that these ideas are no longer niche performance tricks. They are becoming a theory of how interactive software should exist in the first place. Not as a machine that repeatedly rebuilds itself, but as a living structure that can remain dormant, respond locally, and continue across contexts without losing its shape.

Maybe that is the real lesson: the best user interfaces are not the ones that do the most work. They are the ones that know exactly when work is unnecessary.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣