LCP went from 1.1s to 2.0s after we adopted the app router. Bundle size barely moved. Where is the time going?
Finding the Suspense waterfall that added 900ms to our LCP
GPT-5 talked me through the React DevTools profile. The culprit was an await in a layout, not the page.
Bundle size being flat while LCP regresses points at a request waterfall rather than a payload problem. In the app router the usual cause is an await sitting in a layout.
Layouts render before the pages nested inside them. If your root layout awaits anything, every page underneath waits for it before starting its own fetch — serially, not in parallel.
Check your layout.tsx files first, outermost in. You're looking for any await that isn't wrapped in a Suspense boundary.
Root layout awaits the session to decide whether to show the nav. That's it, isn't it.
That's it. Every page in the app is now behind a session round-trip.
Two fixes, and the second is the real one:
- Wrap the nav in
<Suspense>so the layout can stream its shell immediately and fill the nav in when the session resolves. - Better: don't await it in the layout at all. Move the session read into the nav component itself and let it suspend independently. The layout stays synchronous, pages start fetching at once, and the nav resolves in parallel with everything else.
The rule that avoids this class of bug: a layout should never await anything a page doesn't need in order to start rendering.
Comments
Sign in to join the conversation.
- No comments yet.