- Next.js
- Next.js Caching Architecture
- The Client-Side Router Cache & Stale Prefetch Pitfalls
The Client-Side Router Cache & Stale Prefetch Pitfalls
The client-side Router Cache stores rendered React Server Component Flight payloads in browser memory during a user session. When users navigate, Next.js serves pages instantly from this client cache. However, if data changes on the server without client awareness, users see stale UI until the staleTime expires, router.refresh() is called, or a Server Action triggers automatic revalidation.
Learning Objectives
Explain how the browser-side Router Cache improves perceived navigation speed.
Diagnose stale UI bugs caused by Link prefetching and Router Cache retention.
Configure staleTimes in next.config.js to control dynamic and static retention windows.
Force client-side re-synchronization using useRouter().refresh().
Prerequisites & Background Knowledge
Why Interviewers Care
One of the most notorious sources of production bug reports in App Router applications. Tests deep practical experience.
The Challenge
What causes the client-side Router Cache to display stale data after navigation? How do you configure prefetch behavior on <Link> and programmatically force a fresh server render?
Code Architecture & Implementation
1// app/components/Navigation.tsx2'use client';34import Link from 'next/link';5import { useRouter } from 'next/navigation';6import { useTransition } from 'react';78export function NavigationBar() {9 const router = useRouter();10 const [isPending, startTransition] = useTransition();1112 const handleManualSync = () => {13 startTransition(() => {14 // router.refresh() purges the client Router Cache15 // and re-fetches current Server Components from the server16 router.refresh();17 });18 };1920 return (21 <nav className="flex gap-4 p-4 border-b">22 {/* Default: prefetch={true} prefetches full RSC payload on viewport entry */}23 <Link href="/dashboard">Dashboard (Full Prefetch)</Link>2425 {/* prefetch={false}: Prefetches only shared layouts; leaves page dynamic */}26 <Link href="/live-feed" prefetch={false}>27 Live Feed (No Prefetch)28 </Link>2930 <button onClick={handleManualSync} disabled={isPending}>31 {isPending ? 'Syncing...' : 'Force Refresh Data'}32 </button>33 </nav>34 );35}
Architectural Explanation
When <Link> components enter the user viewport, Next.js prefetches their RSC payload and stores it in the client Router Cache. If another user mutates the backend data in the interim, clicking that link renders the prefetched (stale) payload. To fix this: 1) Server Actions should perform mutations, as they automatically invalidate the Router Cache, 2) use router.refresh() when updating via external API or third-party client state, and 3) set prefetch={false} on links pointing to rapidly changing live dashboards.
Common Mistakes & Anti-Patterns
Assuming `window.location.reload()` is required when `router.refresh()` preserves client state and scroll position while re-rendering RSCs.
Leaving `prefetch={true}` on hundreds of links on a single page, flooding the server with prefetch requests.
Thinking `revalidatePath()` in a Route Handler automatically refreshes currently open client browser tabs.
Interview Follow-Up Traps
The interviewer asks: "Does router.refresh() reset client component state (like useState)?" No! Because it streams updated RSC Flight data, React reconciles the tree and preserves existing Client Component state.
Frequently Asked Questions
How does prefetch={false} behave in production?
It only prefetches when the user hovers over the link, rather than when the link enters the viewport.
What is the difference between Router Cache and HTTP browser cache?
The HTTP browser cache stores raw HTML/assets based on Cache-Control headers. The Router Cache stores parsed React Server Component Flight payload trees.
