The Data Cache

Server-Side fetch Results, Stored Forever (Unless Told)

The Data Cache

Next.js caches `fetch` results on the server across requests and across users. You control the TTL with options on each call.

5 min read Level 3/5 #nextjs#cache#data-cache
What you'll learn
  • Recognize that the default `fetch` is cached
  • Use the no-store cache option to opt out
  • Use `next.revalidate` for a TTL and `next.tags` for targeted invalidation

The Data Cache lives on the server and stores the results of every cached fetch Next sees. The same call from different users, requests, and routes all share the same cached response.

The Four Variants

// Cached forever (the default)
await fetch('https://api.example.com/posts')

// Never cached
await fetch('https://api.example.com/posts', { cache: 'no-store' })

// Cached for 60 seconds, then revalidated
await fetch('https://api.example.com/posts', {
  next: { revalidate: 60 },
})

// Cached + tagged for targeted invalidation
await fetch('https://api.example.com/posts', {
  next: { tags: ['posts'] },
})

How It Differs From the Browser Cache

The Data Cache is server-side and persistent across deployments (until invalidated). Two unrelated users hitting the same fetch(url) see the same cached response. The browser’s HTTP cache is per-user; the Data Cache is per-app.

When to Bypass

Anything personalized — user dashboards, authenticated APIs, anything tied to cookies() — should opt out with cache: 'no-store'. Letting personalized data leak through the shared cache is one of the most common Next bugs.

Combining With Tags

// app/posts/page.tsx
const posts = await fetch('https://api.example.com/posts', {
  next: { tags: ['posts'] },
}).then((r) => r.json())

Now any Server Action can call revalidateTag('posts') and every cached entry with that tag is invalidated at once.

The Router Cache →