Interaction to Next Paint (INP) suffers when hydration blocks the main thread. Discover how resumability and deferred hydration solve this bottleneck.
We’ve all been there: a page looks fully loaded, you tap a button, and... nothing. The browser just sits there, frozen, while the JavaScript bundle finishes its massive hydration process. That "dead zone" is the primary culprit behind poor Interaction to Next Paint (INP) scores, and it's where most modern frontend architectures fall apart.
In traditional Server-Side Rendering (SSR) setups, the browser receives static HTML, but the page remains inert until the JavaScript framework re-runs the entire component tree. This process, known as hydration, forces the browser to reconcile the static DOM with the virtual DOM. On low-end mobile devices, this can easily spike the main thread for 500ms or more. If a user clicks during this window, the browser queues the event, and your INP metric tanks.
I previously detailed how improving INP via selective hydration and React Suspense can alleviate some of this pressure by deferring non-critical components. However, even with selective hydration, you’re still paying a tax to "boot up" the framework. To truly solve for responsiveness, we need to rethink whether we need to pay that tax at all.
Resumability is a paradigm shift. Instead of the browser "re-learning" the page state by executing every component, the framework serializes the state and event listeners into the HTML itself. When a user interacts with an element, the framework simply downloads the specific code for that interaction—and nothing else.
This approach effectively eliminates the "hydration phase" entirely. By moving the heavy lifting to the build step or the server, the main thread remains available for user input from the second the page reaches First Contentful Paint.
When we talk about optimizing for Interaction to Next Paint, we’re really talking about keeping the main thread free. If you're stuck in a traditional hydration-heavy framework, you can still adopt "partial hydration" or "island architecture" patterns.
scheduler.yield() to break long tasks into chunks. If you're working with complex DOM trees, INP optimization: architecting non-blocking DOM updates provides a roadmap for keeping the UI thread responsive during these updates.| Strategy | Initialization Cost | Interaction Latency | Complexity |
|---|---|---|---|
| Traditional SSR | High | High (Blocking) | Low |
| Selective Hydration | Medium | Medium | Medium |
| Resumability | Near Zero | Low | High |
| Islands Architecture | Low | Low | Medium |
The biggest win with resumability isn't just about raw speed; it's about stability. In traditional hydration, if your client-side state doesn't perfectly match your server-side HTML, you get a "hydration mismatch," which often leads to jarring layout shifts or broken event handlers. As I've noted in my work on server-side rendering resilience, these mismatches are silent killers of both user experience and performance.
Resumability removes the need for this reconciliation step. The server sends the state, the client picks it up, and the application resumes exactly where it left off.
I’m currently experimenting with frameworks that allow for "progressive enhancement" where the JS is only loaded based on user intent—like hovering over a link or scrolling near a section. It’s an interesting middle ground between the brute force of full hydration and the complexity of pure resumability.
If you’re struggling with INP, don't jump straight into framework migration. Start by profiling your hydration phase using the Performance tab in Chrome DevTools. Look for those long tasks—often caused by useEffect hooks or large state initialization—and see if you can break them up. If the overhead is fundamental to the framework's design, that’s when you start evaluating alternatives.
We're still learning the long-term maintenance costs of resumable architectures. While they solve the INP problem with surgical precision, they often introduce new challenges in how we manage global state and share code between the server and the client. It’s a trade-off, as always.
Learn how to use the Scheduler API to improve Interaction to Next Paint (INP) by mastering task prioritization and keeping your main thread responsive.
Read moreINP optimization requires keeping the main thread free. Learn how to batch DOM updates using document fragments and requestAnimationFrame to prevent long tasks.