Deviopath › Next.js

fetch Cache with Stale-While-Revalidate

Hard · Caching

In Next.js, fetch is not cached by default. fetch(url, { next: { revalidate: 10 } }) opts in to the data cache for 10 seconds, with stale-while-revalidate: once the entry is older than that, the next request still gets the old (stale) value immediately while a background request refreshes the cache. In Next.js 16, revalidateTag(tag, "max") marks tagged entries stale (same SWR behaviour), while updateTag(tag) (Server Actions only) expires them so the next request waits for fresh data.

Write simulateCache(config, versions, ops) for a single cached fetch. This is a simplified model of the data cache; all times are in seconds.

- config is { revalidate, fetchTime }: revalidate is a number or false (cache forever); fetchTime is how long a background refresh takes.

- versions is a list of { from, value } sorted by from: the data source returns the value of the last version with from <= t.

- ops are sorted by t: { t, type: "request" | "revalidateTag" | "updateTag" }.

Rules, applied to each op in order:

- First, if a background refresh is running and t >= its finish time, the cache entry becomes its value, stored at the finish time and no longer marked stale.

- updateTag: delete the entry and cancel a running refresh.

- revalidateTag: mark the entry stale (no effect without an entry).

- request with revalidate: 0: not cached at all, output "SKIP <source value at t>".

- request without an entry: "MISS <value>", the source value at t is stored at t.

- request with an entry that is marked stale or older than revalidate (t - storedAt > revalidate): output "STALE <cached value>". If no refresh is running, start one: it reads the source value at t and finishes at t + fetchTime. Otherwise output "HIT <cached value>".

Return the outputs of the request ops in order.

Next: Split Sitemaps and a Sitemap Index