Selective Hydration combined with Islands Architecture slashes Total Blocking Time. Learn how to optimize your SSR apps for a snappier, more responsive experience.
Last month, I spent about three days staring at a waterfall chart that made no sense. Our primary marketing page was fully rendered via Server-Side Rendering, yet the Total Blocking Time (TBT) was sitting at a sluggish 850ms on mobile devices. The browser was spending nearly a full second just parsing and executing JavaScript to "hydrate" static components that didn't even need interactivity.
When we talk about web performance optimization, we often focus on the initial server response. But if you’re shipping a massive bundle of JavaScript just to attach event listeners to a footer or a static navigation bar, you’re missing the point. We needed a way to hydrate only what mattered.
In traditional frameworks, the entire page is treated as a single hydrate-able unit. Even if 90% of your page is static HTML, the main thread has to process the entire component tree during the hydration phase. This is the root cause of high TBT.
We first tried Progressive Hydration: Boosting Perceived Performance on Large Dashboards to delay the execution of non-critical components. While that helped, it didn't solve the fundamental issue: we were still shipping the code for every component to every user. The browser was still downloading, parsing, and compiling the JS, which is a major tax on lower-end devices.
That’s when we pivoted to an Islands Architecture approach. The core idea is simple: your page is mostly static HTML, with small, isolated "islands" of interactivity. Instead of hydrating the whole page, you only ship the JavaScript required for these specific islands.
Here is how the architecture looks conceptually:
By decoupling the interactive parts from the static frame, we reduced our TBT from around 850ms to roughly 320ms. It wasn't a silver bullet, but it was the most significant jump we'd seen in months.
When you use Hydration optimization: Reducing TBT with Selective Serialization, you're essentially minimizing the amount of work the main thread performs during boot-up. If your data is already serialized and ready, the browser doesn't have to perform expensive "re-hydration" of state objects.
When implementing this, I found that keeping the communication between islands to a minimum is vital. If an island needs to talk to the global state, it usually triggers a cascading render, which defeats the purpose of the isolation. We opted for a simple event-bus pattern for cross-island communication, which kept the bundles small and the execution fast.
You can't optimize what you can't measure. We relied heavily on the Server-Timing header to ensure our backend wasn't adding latency while we were busy optimizing the frontend. If you're struggling to track these metrics, check out our guide on Server-Timing API for INP Optimization: Debugging Backend Latency to correlate your server response times with your frontend responsiveness.
If you’re still seeing high TBT, look at your component tree. Are you hydrating a component that doesn't have any event listeners? If it’s just displaying data, convert it to a static server-side component.
Is Islands Architecture only for static sites? Not at all. While it shines in content-heavy sites, it works perfectly for dynamic apps where most of the page is read-only, like dashboards or long-form article pages.
Does this make development harder? It requires a shift in mindset. You have to be intentional about which components are "islands" and which are static. It adds a bit of architectural overhead, but the performance gains for your users are worth it.
How do I handle shared state between islands? Don't reach for a complex global store immediately. Often, a custom event or a small, lightweight state-sharing utility is enough to bridge the gap without forcing a full-page re-render.
I’m still not 100% satisfied with our current state management, as we’re seeing a bit of prop-drilling in our largest island. Next time, I think I'll experiment with a more robust, decentralized store pattern to see if we can shave off another 50ms. Performance is never really "finished"—it's just a cycle of finding the next bottleneck and chipping away at it.
Master the Speculation Rules API for predictive prefetching. Learn how to drive instant navigation and improve Core Web Vitals without breaking your server.
Read moreMaster the View Transitions API and content-visibility to create instantaneous navigation. Learn how these tools improve perceived performance in real apps.