Performance
medium
mid
How do you reduce Time to Interactive (TTI)?
TTI is the moment the page is reliably responsive. The killer is JS — download, parse, execute, hydrate. Reduce by shipping less JS (RSC, code splitting, tree shaking), avoiding long tasks, deferring non-critical work, and hydrating selectively.
7 min read·~15 min to think through
TTI is the time from navigation start until the page is reliably responsive to input — usually defined as no long task in the next 5 seconds plus all critical scripts loaded.
What makes TTI slow:
- Big JS bundles — download time on slow networks dominates.
- Long tasks — any task > 50ms blocks input. Hydration is the most common culprit.
- Render-blocking resources — synchronous scripts, non-critical CSS in the head.
- Third-party scripts — analytics, chat, ads run on the main thread and steal CPU.
The fix list:
- Ship less JS. Tree shaking, dead-code elimination, RSC (server-only code stays on server), heavy libs (charts, editors) lazy-loaded.
- Code-split by route. Each route loads its own chunk, not the whole app.
- Defer non-critical scripts.
defer/async/requestIdleCallback/scheduler.postTask. Move analytics off the critical path. - Reduce hydration cost. Selective hydration (Astro islands, RSC, partial hydration). Only hydrate interactive components.
- Break long tasks.
yieldToMainpatterns inside long loops. - Preconnect / preload critical origins early.
- Move third-party off main thread. Partytown for analytics, web workers for CPU.
Measure: Lighthouse for lab data, web-vitals library for field. The new metric to watch alongside TTI is INP (Interaction to Next Paint) — captures the worst real-user interaction, not just initial load.
Code
Follow-up questions
- •Why does hydration cost so much, and how does selective hydration help?
- •How does the React Compiler change the JS-payload story?
- •What's the cheapest third-party-script optimization?
Common mistakes
- •Shipping a 500KB main bundle and trying to fix TTI without code-splitting.
- •Lazy-loading critical components so the LCP element waits on a chunk.
- •Letting third-party scripts run synchronously in the head.
Performance considerations
- •Server-render the LCP element as plain HTML, hydrate later. The user sees the page much sooner.
Edge cases
- •Single-page app navigations don't have a 'fresh TTI' — measure long tasks per route change.
- •Slow CPU emulation in DevTools reveals issues that don't show on dev hardware.
Real-world examples
- •Astro's 'islands' architecture and Next.js RSCs were both motivated by hydration-cost-driven TTI.
Senior engineer discussion
Senior signal: discuss perf budgets in CI, RUM-driven optimization, RSC streaming, and how INP supplements/supersedes TTI in the modern toolkit.
Related questions
Performance
Medium
hot
7 min
Performance
Medium
hot
8 min