BitlystBitlyst
PostsSeriesTopicsAbout

Bitlyst

Short, diagram-first posts on JavaScript, React & Next.js. Follow via RSS or the newsletter.

© 2026 Mohsen Fallahnejad

PostsSeriesTopicsLinksAboutRSSGitHubX
Posts/nextjs
Intermediate2 min read

Next.js App Router Caching — Cheat Sheet

A compressed reference of Next.js caching layers and controls (App Router).

Mohsen Fallahnejad

Mohsen Fallahnejad

Sep 20, 2025Discuss

Next.js caches at multiple layers. This guide compresses the official caching docs into a quick reference.


1. The Cache Layers#

  • React Request Memoization
    • Deduplicates repeated fetch calls during a single render.
    • Cleared after render; not persistent across requests.
  • Data Cache (server, persistent)
    • Stores fetch results across requests.
    • Controlled by cache and next.revalidate.
    • force-cache → uses it.
    • no-store → skips it.
    • next.revalidate → ISR-style time-based revalidation.
    • Can also revalidate on-demand (revalidateTag, revalidatePath).
  • Full Route Cache (server)
    • Stores rendered RSC/HTML for static routes.
    • Invalidated when data revalidates or on redeploy.
    • Dynamic routes skip this.
  • Router Cache (client)
    • Stores prefetched RSC payloads for <Link> navigations.
    • Cleared by router.refresh() (client-only).

2. Controlling Caching#

fetch options#

ts
// Always cache (default for static)
await fetch(url, { cache: 'force-cache' })

// Never cache (dynamic)
await fetch(url, { cache: 'no-store' })

// ISR (revalidate every 60s)
await fetch(url, { next: { revalidate: 60 } })

On-demand revalidation#

ts
import { revalidateTag, revalidatePath } from 'next/cache'

// Inside server action or API route
await revalidateTag('products')
await revalidatePath('/dashboard')

👉 In a Server Action, this also clears the client Router cache instantly.

Route-level config#

ts
// Opt out of Full Route Cache (force dynamic render)
export const dynamic = 'force-dynamic'

// Skip all caches
export const revalidate = 0

// Default all fetches to no-store
export const fetchCache = 'default-no-store'

Also: using cookies() or headers() in a route marks it dynamic.


3. What Invalidates What?#

  • Data revalidation (time-based or on-demand) → updates Data Cache + invalidates Full Route Cache.
  • Redeploy → clears Full Route Cache (not Data Cache).
  • router.refresh() → clears only the client Router Cache.

4. Browser vs Server fetch#

  • In browser → cache controls the HTTP cache.
  • In Next.js server → cache controls the Data Cache behavior.

5. Defaults#

  • Static rendering: Data Cache + Full Route Cache enabled.
  • Dynamic rendering: fetch runs every request.
  • <Link prefetch> populates Router Cache automatically.

6. Quick Decision Table#

SituationWhat to do
Always serve fresh (auth dashboards)fetch(..., { cache: 'no-store' }) or export const revalidate = 0
ISR (update every N seconds)fetch(..., { next: { revalidate: N } })
On-demand revalidation (CMS updates)Use revalidateTag / revalidatePath
Force full dynamic renderingexport const dynamic = 'force-dynamic'
Skip client cache after actionCall router.refresh()

⚡ Use no-store for truly dynamic, revalidate for ISR, and revalidateTag/Path for precise invalidation. Combine with route config to balance freshness vs performance.

Filed under#nextjs#caching#app-router#performance

Was this worth your time?

One tap tells me what to write more of.

Mohsen Fallahnejad

Written by

Mohsen Fallahnejad

Frontend engineer explaining JavaScript, React & Next.js internals in posts you can finish over coffee. More about me

X ↗GitHub ↗LinkedIn ↗
← OlderReact useRef vs useState — When to Use WhichNewer →Microtask vs Macrotask in JavaScript — With Node.js vs Browser Notes

Start the discussion

Questions, corrections, a better approach? I read and reply to every comment.

Read next

One Line in My Root Layout Turned 158 Static Pages Into 0

Reading a cookie with cookies() in the Next.js root layout opts every route out of static rendering. What it cost this blog, measured, and how to fix a theme flash without it.

Nov 1, 20267 min read3

Scrolling My Blog Index Prefetched All 51 Posts. One Config Line Cut It to 90 kB.

What a long list of Next.js <Link>s really costs in prefetch requests, measured on this blog, and how partialPrefetching shares one App Shell per route instead.

Nov 3, 20264 min read

CDN Explained: What It Is, How It Works, and How to Use It in Next.js

A CDN speeds up your app by serving assets from servers close to your users. Here's how it works and how Next.js takes advantage of it.

Jun 20, 20263 min read2

Get new posts in your inbox

No spam. Unsubscribe any time.

2 min left
Discuss👍 React
👍