Next.js Wraps fetch With Smart Caching
The Extended fetch API
Next.js extends the standard `fetch` with `cache` and `next` options so you can control caching, revalidation, and tag-based invalidation per request.
What you'll learn
- Set the cache option to force-cache or no-store
- Use the revalidate option for ISR
- Tag responses for targeted invalidation
Next.js patches the global fetch to add caching primitives. The same call can be a
forever cache, a freshness-bounded cache, or always-live depending on the options you pass.
cache: force-cache vs no-store
force-cache memoizes the response indefinitely on the server. no-store opts out — the
request runs on every render.
// Cached forever (until you invalidate)
const data = await fetch('https://api.example.com/posts', { cache: 'force-cache' })
.then(r => r.json())
// Never cached — always live
const live = await fetch('https://api.example.com/now', { cache: 'no-store' })
.then(r => r.json()) Time-Based Revalidation (ISR)
next.revalidate sets a TTL in seconds. After that window, the next request triggers a
background refetch.
const posts = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 }, // refresh at most once per minute
}).then(r => r.json()) This is Incremental Static Regeneration, expressed at the fetch level.
Tag-Based Revalidation
Attach tags to a response so you can invalidate it later by name.
const posts = await fetch('https://api.example.com/posts', {
next: { tags: ['posts'] },
}).then(r => r.json()) You can now call revalidateTag('posts') from a Server Action and every fetch tagged
'posts' becomes stale. That is the bridge to the next lesson.