skip to content

Data Fetching and Caching

Next stacks several caches between your fetch call and the browser, and 'why is my data stale?' is the most common Next bug in the wild. Interviewers want you to name the layers and say precisely which one you would invalidate.

part ofNext.jsoverview, primer and where to startread it →
on this pageshow

explore

questions

27

In a Next.js App Router page.tsx, what does `export const dynamic = 'force-dynamic'` do, and when would you add it?

level: juniorimportance: must knowfreq 62%

answer

  1. a Route Segment Config export
  2. chooses a rendering mode
  3. prerendering turned off for that segment
  4. server render on every request
  5. no stored HTML to replay

basics

~20 s

It is a Route Segment Config export that forces the route to be rendered on the server for every request instead of being prerendered, so its HTML is never served out of Next's Full Route Cache.

solid answer

~50 s

`export const dynamic = 'force-dynamic'` is one of the Route Segment Config exports you can put in a `page.tsx`, `layout.tsx`, or `route.ts`. It tells Next not to prerender that segment: instead of producing HTML at build time (or reusing a stored render), Next runs the server render again on every incoming request. You reach for it when the route genuinely has to reflect something that only exists per request and the page would otherwise be frozen at build time. The important nuance is that it is a *rendering* decision, not a per-fetch cache setting — so still say explicitly how each `fetch` in the page should be cached rather than assuming this export decides that for you. And it is not free: every request now pays a full server render plus whatever data that render waits on.

go deeper

for a junior

Be ready to state in one sentence that this export stops the route being prerendered and makes it render on the server per request, and to name the files it can go in: page.tsx, layout.tsx, route.ts.

for a middle

Explain what it does not do — it picks a rendering mode, it is not a per-fetch cache option and it does not clear stored data — and describe how placement in a layout widens the blast radius to every nested route.

for a senior

Treat it as a cost decision you can defend: say what you measured before and after, why a narrower per-fetch or per-component opt-out was not sufficient, and how the route's origin load now scales with traffic.

for a principal

Own the policy: which routes are allowed to be dynamic by default, how that is reviewed, and what capacity and cost assumptions break when high-traffic pages stop being served from prerendered output.

## What the export actually is Next's App Router lets a route segment configure itself by exporting specific named constants from `page.tsx`, `layout.tsx`, or `route.ts`. These are called Route Segment Config options, and `dynamic` is one of them: ```tsx // app/orders/page.tsx export const dynamic = 'force-dynamic' export default async function Page() { return <main>rendered on every request</main> } ``` The accepted values are `'auto'` (the default), `'force-dynamic'`, `'error'`, and `'force-static'`. `'force-dynamic'` is the deliberate opt-out: it says "do not prerender this segment; render it at request time." ## Static vs dynamic rendering, in one paragraph A route that is *statically rendered* is executed ahead of the user — at build time, or once and then reused — and the resulting HTML/RSC payload is stored and replayed. That stored render is what Next calls the Full Route Cache, and it is the reason a Next site can serve pages without touching your server or your database at all. A route that is *dynamically rendered* runs the component tree fresh on each request, so nothing about it can come out of that stored render. `force-dynamic` moves a route from the first category to the second. That is its entire job. ## When you actually want it - The page must show something that only exists at request time and there is no prerenderable version of it worth shipping. - The page is per-user and there is no meaningful shared HTML to store. - You are debugging a staleness bug and want to eliminate rendering-level caching as a variable before narrowing the fix down again. Notice how narrow that list is. `force-dynamic` is a blunt instrument at *segment* scope — every data read in that segment re-runs, not just the one that was stale. ## What it does not do Three misreadings show up constantly in interviews: 1. **It is not related to dynamic route segments.** A folder named `app/orders/[id]` is a *dynamic segment* — a URL parameter. The `dynamic` config export is about *rendering mode*. The word collision is unfortunate and interviewers enjoy it. 2. **It is not a global cache purge.** It does not empty Next's Data Cache, it does not invalidate anything you previously stored, and it does not reach into other routes. It changes how *this* segment renders. 3. **It is not a per-request cache setting for your `fetch` calls.** Caching of individual data reads is decided by the options you pass to those reads. Treat rendering mode and data caching as two separate decisions you make explicitly; that habit survives version changes in Next's defaults, whereas "force-dynamic sorts out my fetches too" does not. ## Where you put it matters Placement decides blast radius. In a leaf `page.tsx` it governs that one route. In a `layout.tsx` it governs the routes rendered inside that layout — and the root layout is rendered inside *every* route, so a `force-dynamic` there means nothing in the app can be served as a prerendered document any more. That is the single most common way a Next app quietly loses all of its static output. It also has no effect in a file marked `'use client'`. Route Segment Config is read from server-rendered route files; exporting it from a client component is silently useless, which makes for a frustrating afternoon. ## The cost A prerendered route can be served from a stored artifact — often from a CDN edge, with no server work at all. A dynamic route cannot. Every request now: - runs your server components again, - waits on whatever those components await, - and produces bytes that a shared cache in front of you cannot reuse unless you separately tell it to. So TTFB becomes "however long your data layer takes", and your origin capacity now scales with traffic instead of with how often content changes. That is a real trade, and it is exactly the follow-up an interviewer asks after you explain the mechanism: *what did you give up?* The good answer is that you reach for the narrowest opt-out that fixes the actual bug, and you only go segment-wide when the whole segment truly is per-request.

  • Does exporting it from a file that starts with 'use client' do anything?
    No. Route Segment Config is read from the server-rendered route files — `page.tsx`, `layout.tsx`, `route.ts`. Exporting `dynamic` from a client component is silently ignored, so the route keeps whatever rendering mode it had. This is a common source of "I set force-dynamic and nothing changed" reports; check which file the export actually lives in.
  • What changes if you put it in the root layout instead of one page?
    The root layout is rendered inside every route, so making it dynamic means no route in the app can be served as a prerendered document. You lose static output everywhere, and origin load jumps for pages that never needed freshness. Keep the opt-out at the lowest segment that actually needs it.
  • How would you confirm the route really is rendering per request?
    Check the `next build` output, which labels each route as prerendered or rendered on demand — that is the authoritative answer for the deployed build. In development, logging a timestamp or a request-scoped value in the server component and watching it change on every reload is a quick sanity check, but the build output is what you cite.

saying these in an interview costs you the question

  • Confuses it with dynamic route segments like [id]
  • Claims it purges Next's Data Cache app-wide
  • Thinks it also decides how each fetch is cached
  • Exports it from a 'use client' file and expects an effect
  • Puts it in the root layout to fix a single page

context

open as a page

A Next.js App Router page exports `export const revalidate = 3600`. Does Next.js rebuild that page once an hour on a schedule? Explain what actually triggers the rebuild.

level: juniorimportance: must knowfreq 62%

basics

~20 s

No scheduler is involved. The number is a staleness window in seconds: after 3600 seconds the cached page is merely marked stale, and only the next incoming request for that route causes Next.js to regenerate it.

open as a page

In the Next.js App Router, what does passing `{ cache: 'force-cache' }` to `fetch` inside a Server Component do, and is that already what a plain `fetch` with no options does?

level: middleimportance: must knowfreq 78%

basics

~20 s

Passing cache: 'force-cache' stores that fetch's response in Next's server-side Data Cache so later requests reuse it instead of calling the origin. In Next 15 and 16 that is not the default: a bare fetch is uncached.

open as a page

A Next.js App Router Server Component calls `fetch(url, { next: { revalidate: 60 } })`. What exactly does that 60 apply to?

level: middleimportance: must knowfreq 66%

basics

~20 s

The 60 seconds belongs to that one Data Cache entry — the one keyed from that URL and those options — not to the component, the page, or any other fetch. Supplying it also opts the fetch into caching.

open as a page

The Next.js App Router is usually described as having four caching layers. Name them, and for each say where it physically lives and how long an entry lasts.

level: middleimportance: must knowfreq 70%

basics

~20 s

Four layers: Request Memoization (one render pass, server memory), the Data Cache (persistent server store of fetch results), the Full Route Cache (prerendered route output on the server), and the Router Cache (visited segments in browser memory for the session).

open as a page

In Next.js, what is the difference between calling `revalidatePath('/blog')` and `revalidateTag('posts')` from `next/cache`, and what does the tag version buy you that the path version cannot?

level: middleimportance: must knowfreq 72%

basics

~20 s

revalidatePath invalidates cached output by route path, so you must know every URL affected by a change. revalidateTag invalidates every cached entry labelled with that tag, wherever it lives, so one call can refresh many routes at once.

open as a page

In a deployed Next.js App Router app, a user edits a record; reloading the list page shows the new value, but navigating back to that list with a <Link> still shows the old one. Which caching layer is holding the stale copy, and how would you confirm it?

level: seniorimportance: must knowfreq 55%

basics

~20 s

The client-side Router Cache. It keeps the payload of already-visited route segments in browser memory, so a soft navigation renders from memory while a full reload discards it and goes to the server. Confirm by checking that other browsers and direct server responses are fresh.

open as a page

In a Next.js App Router app, a developer adds `'use cache'` to a function that calls `cookies()` to read the session and returns that user's dashboard data. What does Next.js do about that, and how should the code be restructured?

level: seniorimportance: must knowfreq 52%

basics

~20 s

Next.js rejects it: request-time APIs such as cookies() and headers() cannot be called inside a 'use cache' function, because a cached entry is shared across requests and would hand one user's data to another. Read the session outside the cached function and pass the values you need in as arguments.

open as a page

A Next.js component marked `'use client'` calls `fetch('/api/report', { next: { revalidate: 60 } })` inside a `useEffect`. Does that response end up in Next's Data Cache?

level: juniorimportance: should knowfreq 45%

basics

~20 s

No. That call runs in the browser, where fetch is the platform's own function and the Next-specific next option is simply ignored. Next's Data Cache is a server-side store that browser requests never write to.

open as a page

In a deployed Next.js App Router app, two different users request the same page. Which of Next.js's caching layers can serve both of them from the same stored copy, and which one is private to a single browser?

level: juniorimportance: should knowfreq 45%

basics

~20 s

The two server-side layers — cached fetch responses and stored route output — are shared, so both users can be served the same copy. The browser's Router Cache is private to one session, and per-render memoization is scoped to a single render so nobody else ever sees it.

open as a page

In Next.js, what does adding the `'use cache'` directive at the top of a file, an async function, or a component actually do?

level: juniorimportance: should knowfreq 48%

basics

~20 s

The 'use cache' directive marks a file, async function, or component as cacheable. Next.js runs it once, stores the returned value on the server under a key derived from its inputs, and reuses that value on later requests until it is revalidated.

open as a page

In the Next.js App Router, what does `next: { tags: ['products'] }` on a `fetch` actually do, and what must be true of that fetch for the tag to have any effect?

level: middleimportance: should knowfreq 48%

basics

~20 s

The tag is a label written onto the Data Cache entry that fetch creates, so the entry can later be invalidated by name. It does nothing unless the fetch is actually cached — an uncached fetch stores no entry to label.

open as a page

In a Next.js App Router page, a layout and two Server Components each call fetch('https://api.example.com/user') while rendering the same request. How many requests actually leave the server, and what does that deduplication not do for you?

level: middleimportance: should knowfreq 50%

basics

~20 s

One. React memoizes fetch calls with the same URL and options within a single server render, so the three calls collapse into one. That memoization is scoped to that one render: it is not shared across requests, users, or non-fetch data access.

open as a page

A Next.js App Router dashboard showed one stale number, and a teammate fixed it by adding `export const dynamic = 'force-dynamic'` to the page — but only one of that page's six data reads has to be fresh. What narrower opt-outs were available, and what did the broad fix cost?

level: middleimportance: should knowfreq 52%

basics

~20 s

Opt out at the narrowest scope that fixes the bug: no-store on the one fetch, or connection() in the one component that must run per request. Forcing the whole segment dynamic re-runs all six reads on every request and ends prerendering for the route.

open as a page

A Next.js App Router page is cached with a one-minute time-based revalidation window. Hours after the underlying data changed, a visitor loads the page and still sees the old content; they reload once and now see the new content. Explain what Next.js served on each of those two requests.

level: middleimportance: should knowfreq 55%

basics

~20 s

The first request found an expired cache entry, was served the stale copy immediately, and triggered a background regeneration. That regeneration finished and replaced the entry, so the reload was served the newly rendered page.

open as a page

In Next.js, what does calling `cacheLife()` from `next/cache` inside a function marked `'use cache'` control, and what do the `stale`, `revalidate` and `expire` values of a cache profile mean?

level: middleimportance: should knowfreq 34%

basics

~20 s

cacheLife() sets the lifetime profile of a 'use cache' entry. Its three values separate concerns: stale is how long a client may reuse the value without re-checking, revalidate is how often the server refreshes it in the background, and expire is the maximum age past which the value can no longer be served.

open as a page

A Next.js function marked with the `'use cache'` directive takes arguments and also reads a variable from its enclosing scope. What forms the cache key, and what does that require of the arguments and of the returned value?

level: middleimportance: should knowfreq 40%

basics

~20 s

Next.js keys a 'use cache' entry on everything that flows into the call: the serialized arguments plus the values the function closes over. Both must be serializable to be part of the key, and the returned value must be serializable because it is what gets stored and replayed.

open as a page

In a Next.js server render, what does React's `cache()` function do, and how does that differ from marking the same function with Next's `'use cache'` directive?

level: middleimportance: should knowfreq 44%

basics

~20 s

React's cache() deduplicates calls within a single server render: several components asking for the same data run the work once, and the memo is discarded when the render ends. Next's 'use cache' stores the result in a persistent server cache that survives across requests and users until it is revalidated.

open as a page

In a Next.js App Router Server Component, a developer adds `cache: 'force-cache'` to a fetch of an endpoint that returns the signed-in user's own profile. Why is that dangerous, and what decides whether two different visitors hit the same cached entry?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Next's Data Cache is one server-side store shared by every request, and its entries are keyed from the fetch URL plus the options passed. If nothing in that key varies per user, the first visitor's profile is served to everyone else.

open as a page

You deploy a new build of a Next.js App Router app. Which of Next.js's caching layers survive that deployment and which are thrown away?

level: seniorimportance: should knowfreq 42%

basics

~20 s

The persistent server data layer is designed to survive a deployment, so cached responses come back after the new build ships. Stored route output is a build product and is replaced. Per-render memoization is irrelevant, and the browser's Router Cache lives in each open tab until it reloads.

open as a page

After a stale-data fix, a Next.js App Router app that used to prerender most of its routes now builds with almost every route rendered on demand, and TTFB and origin CPU are up. How do you find what turned prerendering off, and how do you get it back?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Read the build output to see exactly which routes went dynamic, then look for an opt-out placed too high: force-dynamic or revalidate = 0 in a shared or root layout, an awaited connection() in a shared component, or a no-store buried in a helper every page imports. Push it down to the one place that needs it.

open as a page

A Next.js App Router site prerenders its marketing pages from a headless CMS, and editors complain that a publish takes up to an hour to appear on the live site. Design the path from a CMS publish event to the updated page in production.

level: seniorimportance: should knowfreq 48%

basics

~20 s

Have the CMS call a Route Handler in the deployed app on publish. The handler verifies a shared secret, maps the payload to the tags or paths the change touches, calls revalidateTag or revalidatePath, and returns quickly. Keep a time window as a backstop.

open as a page

Your team is upgrading a Next.js App Router codebase from Next 14, where `fetch` in Server Components was cached by default, to Next 15 or later, where it is not. How do you decide which fetches to opt back into the Data Cache?

level: principalimportance: should knowfreq 30%

basics

~20 s

Do not restore the old default globally. Classify each fetch by whether its response is shared across all users and how stale it may be, opt in only the shared ones with force-cache or an interval, and treat the upgrade as the moment to make caching intent explicit.

open as a page

Your team is upgrading a large Next.js App Router app to a version where server caching is opt-in rather than applied by default, and routes that used to be static now do work on every request. How do you decide what gets `'use cache'`, and how do you roll that out?

level: principalimportance: should knowfreq 24%

basics

~20 s

Treat it as a data-classification exercise, not a search-and-replace. Measure which routes actually regressed, cache the expensive user-independent work first with explicit lifetimes and tags, leave request-specific work uncached, and roll out route by route with staleness and hit-rate signals in place.

open as a page

What does `connection()` from `next/server` do when awaited in a Next.js App Router server component, and what does it solve that a fetch cache option cannot?

level: middleimportance: nice to knowfreq 32%

basics

~20 s

Awaiting connection() tells Next that rendering must wait for a real user request, so everything after it is excluded from prerendering. It is the opt-out for code with no data fetch at all, such as a component reading the clock or a random value.

open as a page

After a stale-pricing incident, a team adopts a rule that every Next.js App Router route carries `export const dynamic = 'force-dynamic'` so nothing can ever be stale. How would you evaluate that policy?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

The rule buys less correctness than it looks like and costs more than the team expects: rendering per request does not guarantee a user sees fresh data, while every route now pays a server render and origin capacity scales with traffic instead of with content change.

open as a page

You own a large Next.js App Router site whose routes are all cached. For each kind of content, how do you decide between a time-based revalidation window and event-driven invalidation, and how do you choose how fine-grained your cache tags should be?

level: principalimportance: nice to knowfreq 32%

basics

~20 s

Decide per content type from an explicit staleness budget: windows where being minutes old is acceptable and no change event exists, event-driven invalidation where a change must be visible immediately or a reliable publish event already exists. Size tags to real change events.

open as a page