ZeroBuffer
PricingDocsNetworkBlogsContact
Sign inStart free
ZeroBuffer
PricingDocsNetworkBlogsContact
Sign inStart free
Tools/Cache-Control generator

Cache-Control header generator

Build the header from toggles, read what every directive means, and see which of them cancel each other out. Cache-Control has no validator — a contradictory combination is not an error, just a silently applied precedence rule — so the lint pass is the part that matters.

Start from a common case

Your header

Cache-Control: public, max-age=31536000, immutable
Who may store it
Freshness
seconds — 1 year
Revalidation
Serving stale

What this header actually does (1)

  • immutable is only safe on a content-addressed URL

    It tells caches not to revalidate even on a manual reload, which means a wrong file is unfixable at the edge — you cannot purge a browser cache. Only use it where the filename contains a hash of the contents (app.4f2b9c.js, or a versioned media segment), so that changing the bytes changes the URL.

Directive by directive

public
Any cache may store this, including shared caches like a CDN — even when the request carried an Authorization header, which would otherwise make the response private by default.
max-age=31536000
Fresh for 1 year after it was generated. Any cache may serve it without contacting the origin until then.
immutableRFC 8246 extension
The body will never change while fresh, so a cache should not revalidate even when the user presses reload. This is the directive that stops a reload from firing hundreds of pointless conditional requests.

Setting it

location ~* \.(js|css|woff2|m4s|ts)$ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
}

Why contradictory directives are so common

Nothing rejects a bad Cache-Control. There is no schema, no build step, and no warning in any server — a header that stores nothing and a header that caches for a year look equally valid on the way out. The two most common failures are no-store arriving alongside a long max-age, usually because a framework default and an explicit override both applied, and immutable on a URL whose contents can change in place.

The second one is the expensive mistake. immutable suppresses revalidation even on a manual reload, and no purge reaches a browser cache. Ship the wrong bytes at a stable URL with a year-long lifetime and the only fix is waiting, or changing the URL.

The shapes worth knowing

Hashed assets and media segments take public, max-age=31536000, immutable, because the filename changes when the bytes do. HTML usually wants max-age=0 with a longer s-maxage, so the edge holds it while the browser always checks. A live HLS media playlist needs a lifetime shorter than its segment duration, or the edge will serve a manifest that is missing the newest segments.

To see what a URL is doing today rather than what it should do, the cache header checker reads the real response and grades it. For what a cache miss costs, the CDN cost calculator puts a number on the origin egress a low hit ratio produces.

Frequently asked questions

What is the difference between no-cache and no-store?
no-store forbids writing the response to storage at all — nothing is kept, anywhere. no-cache does allow storage, but requires the cache to revalidate with the origin before serving what it holds. Despite the name, no-cache still caches: it just never serves without checking first, which is far cheaper than re-downloading because an unchanged resource comes back as a bodyless 304.
What is the difference between max-age and s-maxage?
max-age applies to every cache, including the user's browser. s-maxage applies only to shared caches such as a CDN, and overrides max-age for them. The pair exists so you can hold something at the edge for hours while keeping the browser copy short-lived — max-age=0, s-maxage=3600 is the common shape for HTML.
When is it safe to use immutable?
Only when the URL changes whenever the content changes — a filename containing a content hash, like app.4f2b9c.js, or a versioned media segment. immutable tells caches not to revalidate even when the user presses reload, so a wrong file cannot be corrected by purging: browsers that already hold it will keep it until max-age expires. On a URL whose content can change in place, it is a trap.
Does Cache-Control: no-store, max-age=31536000 cache anything?
No. no-store forbids storage outright, so there is nothing for max-age to describe a lifetime for. The header looks like aggressive caching and delivers none — it is one of the most common accidental combinations, and usually appears when a framework default and an explicit override are both applied to the same response.
What does stale-while-revalidate do?
It defines a window after expiry during which a cache may serve the stale copy immediately and fetch a fresh one in the background. The user never waits for the origin, which removes the latency spike that otherwise hits whoever happens to request a resource the moment it expires. It is defined in RFC 5861 as an extension, so support varies — most major CDNs implement it, and browser support is narrower.
Do I still need ETag or Last-Modified if I set Cache-Control?
Yes, for anything that is revalidated rather than simply re-downloaded. Cache-Control decides how long a response stays fresh; a validator decides what happens after that. Without one, an expired entry must be fetched in full, whereas with one the cache sends a conditional request and usually gets a 304 with no body at all.

ZeroBuffer™

High-performance CDN, storage, streaming and optimization — built for global scale.

Product

  • Home
  • About Us
  • Features
  • Network
  • Use Cases
  • Pricing
  • Contact Us

Solutions

  • CDN for OTT
  • CDN for Gaming

Company

  • Blogs
  • Contact
  • Careers

Legal

  • Privacy Policy
  • Terms of Service
  • Acceptable Use Policy
  • Refund Policy
  • Report Abuse
© 2026 Apexnova Private Limited. All rights reserved.