loading.tsx never renders on client nav but works on hard refresh, 3s of nothing Streaming
Next 15.3, app/(dash)/reports/loading.tsx. If I paste the URL in the address bar and hit enter I get the skeleton immediately, then the page. If I click the <Link> from the sidebar I get nothing at all - the old page just sits there for about 3 seconds and then the reports page appears.
The slow part is a ClickHouse query that takes 2.6s. I expected the skeleton either way. Am I misunderstanding what loading.tsx does on a client-side transition, or is something in my tree defeating it?
@awkward_ash · 5d ago · 3 replies
loading.tsxonly covers the segments below it. If the 2.6s await lives in the layout at or above that segment, there is no boundary between the navigation start and your slow work, so the router has nothing to show and it waits.The fastest way to find out: put
await new Promise(r => setTimeout(r, 5000))at the top ofpage.tsxand click the link. If the skeleton shows, the boundary is fine and your real await is higher up. If it still hangs, the await is in the layout.Either way the fix is the same shape - stop awaiting in the layout, move the slow component into the page and wrap it yourself:
Reply
Report
@quiet_stacker · 5d ago
It was the layout.
(dash)/layout.tsxawaits a workspace lookup for the sidebar, which normally takes 40ms so I never noticed, but the client transition waits for the whole layout payload before it commits. Moved the lookup into the sidebar component behind its own Suspense and the skeleton shows instantly now.Reply
Report
@lowtech_lior · 3d ago
This is the one thing I wish were louder in the docs: a layout is not free, it is on the critical path of every navigation into it, and it does not re-render but it does have to resolve.
Reply
Report