AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

App Router Repeatedly Retries Hydration While A Client Component Chunk Is Loading

On cold load with a delayed client component chunk, Next.js App Router repeatedly retries root hydration causing thousands of empty commits and significant main thread time. The issue is triggered by `useDeferredValue` calls in `Head` and `InnerLayoutRouter` that pass the current RSC value as the initial value even when no prefetch data exists during initial hydration. This leads to React scheduling deferred work that commits an empty tree, making hydration eligible to retry in a loop.

highConfidence 95%Next.jsAffected V16.5.0-Canary.2Affected V16.3.8

Origin Analysis

`useDeferredValue` in `Head` and `InnerLayoutRouter` is called with a second `initialValue` argument equal to the current value even when `prefetchRsc` is `null` (during initial hydration). React's current implementation treats this as a request to schedule deferred work, which commits an empty tree while the root is suspended waiting for a client component chunk. That empty commit makes hydration eligible to retry, repeating the cycle until the chunk arrives. Underlying React behavior is tracked in react/react#37682.
1. Clone https://github.com/filipzapletalcs/next-head-deferred-hydration-repro 2. Run `npm install && npx playwright install chromium` 3. Build and start production server: `npm run build && npm start` 4. In another terminal run `npm run measure -- --cpu 1 --network none --hold-ms 1500` to artificially delay the `<Heavy />` client component chunk for 1.5 seconds. 5. Observe via React DevTools hook that hydration retries and empty commits occur until the chunk arrives.

Fixing Code Block

Edge Case Audit

This change relies on React 19's `useDeferredValue` semantics where omitting the `initialValue` avoids scheduling a deferred update when no prior value is needed. It is safe for the reported versions but could behave differently in older React versions that do not support the optional second argument or have different deferred scheduling. Rollback is straightforward: revert the two lines to always pass `prefetchRsc` as second argument. No persistence or data loss is involved.

Ecosystem Topology