Model the Client Router Cache
Hard · Caching
The App Router keeps the pages you visited or prefetched in an in-memory client cache, so navigating with <Link> can reuse them instead of asking the server again. How long an entry may be reused is set by staleTimes in next.config (seconds): dynamic (default 0) for dynamic pages, static (default 300) for static pages and for pages that were fully prefetched (router.prefetch(href) or <Link prefetch={true}>). Back/forward navigation always reuses the cache so the page and scroll position do not jump, and router.refresh() clears the client cache of the current route and fetches it again.
This is a simplified model: the real cache stores route segments rather than whole pages, and Next.js 16 rewrote prefetching (layout deduplication, incremental prefetching). Implement class RouterCache with constructor(config, routes, start); routes maps a path to static or dynamic (unknown paths are dynamic). All times are in ms.
- The start page is loaded at time 0: it is the first history entry and cached with fetchedAt: 0, not fully prefetched.
- An entry is fresh when now - fetchedAt < staleTime * 1000, where staleTime is static if the route is static or the entry came from a prefetch, else dynamic.
- prefetch(path, now): "skip" if a fresh entry exists; otherwise store { fetchedAt: now, prefetched: true } and return "prefetch". History does not change.
- link(path, now): push path onto the history (dropping any forward entries). A fresh entry gives "cache" (the entry stays as it is); otherwise store { fetchedAt: now, prefetched: false } and return "fetch".
- back(now) / forward(now): "none" if there is nowhere to go. Otherwise move in the history and return "cache" if the target has an entry, even a stale one; if it was evicted, store a fresh entry and return "fetch".
- refresh(now): replace the current route's entry with { fetchedAt: now, prefetched: false } and return "fetch". Other entries are untouched.
- The cache is bounded (Next.js uses an LRU): it holds at most config.maxEntries routes. Storing an entry or serving one from the cache ("cache" results) makes it the most recently used; when a new route would exceed the limit, evict the least recently used one.