Router Cache Staleness vs. staleTimes.dynamic: Trade-Off for Navigational Freshness in Next.js 15+
0 reputation · 17 Mar 2021, 15:21 UTC
0 reputation · 17 Mar 2021, 15:21 UTC
In Next.js 15+ App Router, users navigating back to a previously visited route may see outdated list items or timestamps instead of fresh server-rendered content. This stems from the Router Cache's per-segment payload storage in the browser session, which serves cached RSC responses on back-forward navigation without contacting the server. The concrete constraint balances instant navigational performance against data freshness when routes are revisited after mutations or time-sensitive updates.
In Next.js 15, dynamic segments are no longer stale by default, while static segments keep a longer caching window. Link prefetching can populate the Router Cache before user interaction, making staleness visible on first visits. The trade-off favors longer staleTime for navigation speed, or staleTimes.dynamic zero and no-store fetches for fresh payloads at the cost of perceived latency. Documentation does not prescribe a single correct choice, and the interaction between Route Cache, Data Cache, and Router Cache means disabling one layer does not alone ensure fresh output.
31275 reputation · 17 Mar 2021, 19:30 UTC
Routes that display user-specific or time-sensitive data—such as dashboards, live feeds, or authenticated lists—require fresh data on every revisit. Static or marketing-oriented pages can typically tolerate the default stale window without user-visible staleness.
staleTime.staleTimes.dynamic: 0 in configuration forces the Router Cache to treat those segments as fresh, bypassing the cache on navigation.staleTimes to 0 does not guarantee fresh output if the underlying data fetches use the default caching (cache: 'force-cache').router.refresh() and revalidatePath() clear the Router Cache but do not inherently invalidate the Data Cache unless combined with tag-based revalidation.Even with staleTimes.dynamic = 0, a navigation will trigger a network request for the RSC payload. However, if the data fetches within that segment use default caching, the Data Cache may return a previously stored JSON response. This results in a "stale-while-revalidate" window per fetch. To ensure absolute freshness, you must use cache: 'no-store' or revalidateTag to bypass that data-layer cache.
Rely on router.refresh() or revalidatePath() mutations when:
staleTime for most routes to preserve navigation speed, only invalidating specific paths on demand.no-store to every fetch would introduce unacceptable uniform latency across the app.// next.config.js
module.exports = {
experimental: {
staleTimes: {
dynamic: 0, // Force fresh Router Cache for dynamic segments
},
},
};
// Example dynamic segment fetch with no-store
export async function fetchData() {
const res = await fetch('https://api.example.com/items', { cache: 'no-store' });
return res.json();
}
To verify your setup:
next dev --debug and monitor the DevTools Network tab.no-store headers or is revalidated.no-store to the fetch.Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.