webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
Next.js · Lesson 7 of 12

Caching: 'use cache', tags and PPR

Cache Components, cacheLife, cacheTag, updateTag vs revalidateTag.

Updated

What a cache is

A cache = you keep the result of an expensive operation (a DB query, an API request, a render) so you don't redo it on every request. The result: instant pages and less load on the server.

The price: cached data can go stale. That's why every cache needs an invalidation strategy — when to throw away the old copy.

Cache Components (Next 16)

The model in Next 16, enabled in next.config.ts:

const nextConfig = { cacheComponents: true, partialPrefetching: true }

The rule: nothing is cached by default. You explicitly mark what gets cached, with the 'use cache' directive.

'use cache'

import { cacheLife, cacheTag } from 'next/cache'

export async function getPosts() {
  'use cache'
  cacheLife('hours')       // how long it lives
  cacheTag('posts')        // a tag for invalidation
  return db.post.findMany()
}
  • The function's arguments automatically become part of the cache key: getPost(1) and getPost(2) are separate entries.
  • It goes on data functions, on components or on a whole page.
  • You can't read cookies() / headers() inside it — you read them outside and pass the value as an argument.

The cacheLife profiles

Profile Revalidation Expiry For
seconds 1s 1 min near-live (becomes dynamic)
minutes 1 min 1 h feeds, prices
hours 1 h 1 day editorial content (the lessons here)
days 1 day 1 week rarely changing pages
max 30 days 1 year almost static

What Partial Prerendering is

PPR combines static and dynamic in the same page:

  1. At build time, Next renders everything it can (including what's in 'use cache') → a static shell, served instantly from a CDN.
  2. The dynamic parts (in <Suspense>, reading cookies etc.) are rendered at request time and streamed.

Exactly this app: the lesson is in the static shell; your progress (from a cookie) is streamed in.

The output of npm run build shows each route's type: ○ static, ◐ partial prerender, ƒ dynamic.

Invalidation — kinds and when

Function Where Behavior When
updateTag('posts') only Server Actions expires immediately; the next request waits for new data the user changed something and must see it right away (read-your-own-writes)
revalidateTag('posts', 'max') Server Actions + Route Handlers stale-while-revalidate: serves the old one, refreshes in the background content from a CMS / a webhook — a small delay is fine
revalidatePath('/blog') the same invalidates a whole route you don't have suitable tags
refresh() Server Actions refetches the current page's dynamic data after mutations without a cache tag (like saving progress here)

Summary

  • Nothing is cached by default; 'use cache' + cacheLife + cacheTag, explicitly.
  • PPR = an instant static shell + dynamic parts streamed in.
  • updateTag for the user who just made a change; revalidateTag(tag, 'max') for everything else.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.