Back to all notes
Next.js
2 weeks ago

Cache-Control for committed static art: never immutable

Committed, non-fingerprinted art should be cached with stale-while-revalidate, never immutable — a regenerated asset at the same path must still refresh.

The trap

Cache-Control: immutable is the right answer for fingerprinted build assets: app.3f9a2.js never changes, so cache it forever. It is the wrong answer for art you commit at a stable path. If /images/article-cover.png is immutable and you regenerate it, browsers that saw the old one keep it indefinitely — there is no hash in the URL to bust.

What this site sends

The non-fingerprinted art under /images and /logos gets a middle path instead: cache for a day, then serve stale while revalidating for a week.

{
  source: "/:dir(images|logos)/:path*",
  headers: [{
    key: "Cache-Control",
    value: "public, max-age=86400, stale-while-revalidate=604800",
  }],
}

Why stale-while-revalidate

It is the best of both. Within the day, the asset is served straight from cache — fast, no request. After it, the browser serves the stale copy and revalidates in the background, so a regenerated image refreshes on the next visit without ever blocking a paint on a network round-trip. immutable gives you the speed and never the refresh.

The rule

Fingerprint in the filename, then immutable. Stable path, then stale-while-revalidate. The mistake is reaching for immutable because it sounds the most aggressive — aggressively caching a mutable URL is just a bug with a long TTL.

#next.js#caching#http#performance
Found this useful?

Related notes