📋 listicle

5 Cache-Control Directives Worth Knowing

Understanding max-age, s-maxage, no-cache, no-store, and stale-while-revalidate — how HTTP caching headers control browser and CDN behavior.

5 Cache-Control Directives Worth Knowing

The Cache-Control header controls how browsers and CDNs cache HTTP responses. It's powerful — but also confusing if you don't know what each directive actually does.


Here are five Cache-Control directives worth understanding, explained in plain English. We'll cover how they work, when to use them, and what traps to avoid.


1. max-age — Freshness Lifetime in Seconds


What it does:


max-age tells caches how long a response can be reused without checking with the origin server. The value is in seconds.


Cache-Control: max-age=3600


This says: "You can reuse this response for up to 3600 seconds (1 hour) without asking me again."


Applies to both browser and CDN:


max-age applies to both private caches (your browser) and shared caches (CDNs, proxies). If you want different behavior for each, see s-maxage below.


Age header subtracts elapsed time:


If a CDN has already stored the response for 600 seconds, the browser sees:


Cache-Control: max-age=3600

Age: 600


The browser knows the response has 3000 seconds of freshness left (3600 - 600).


When to use it:


Use max-age for static assets (CSS, JavaScript, images) that change infrequently. Longer values reduce origin requests; shorter values keep content fresher.


Related: What Is Caching? explains the basics of HTTP caching.


2. s-maxage — Shared-Cache Override


What it does:


s-maxage (shared max-age) overrides max-age and Expires for shared caches only — like CDNs and proxies. Private caches (browsers) ignore it.


Cache-Control: max-age=60, s-maxage=3600


This means:


  • Browsers cache for **60 seconds**
  • CDNs cache for **3600 seconds (1 hour)**

  • Why this matters:


    You might want CDNs to cache aggressively (to reduce origin load) while keeping browser caches short (so users see updates sooner). s-maxage lets you control each independently.


    Implies proxy-revalidate semantics:


    According to RFC 9111, s-maxage implies that shared caches should not serve stale responses, even if stale-while-revalidate is also set. CDN behavior varies — some honor stale-while-revalidate anyway, some don't. Check your CDN's documentation before relying on this.


    Private vs public consideration:


    If your response is personalized (user-specific data), use Cache-Control: private to prevent CDNs from caching it at all. private means only the browser cache can store it. public explicitly allows shared caches, but is usually not needed unless you're overriding default behavior for authenticated responses.


    Related: What Is a CDN? explains how CDNs cache content.


    3. no-cache — Must Revalidate Before Reuse


    What it does:


    Despite the name, no-cache does NOT mean "don't cache." It means: you can store this response, but you must check with the origin server before reusing it.


    Cache-Control: no-cache


    How revalidation works:


    When the cache needs to serve the response again, it sends a conditional request to the origin:


    GET /resource HTTP/1.1

    If-None-Match: "etag-value"


    If the resource hasn't changed, the server responds with 304 Not Modified — no body, just headers. The cache then serves the stored response. This saves bandwidth compared to re-downloading the entire response.


    The misleading name:


    The name no-cache confuses people. If you want to prevent caching entirely, use no-store (see below).


    From MDN:


    > Note that no-cache does not mean "don't cache". no-cache allows caches to store a response but requires them to revalidate it before reuse.


    When to use it:


    Use no-cache when content must be fresh but bandwidth matters. Pair it with ETag or Last-Modified so revalidation can avoid re-sending unchanged content.


    Related: no-cache vs no-store: What's the Difference? goes deeper into these two directives.


    4. no-store — Must Not Store the Response


    What it does:


    no-store tells caches — private and shared — that they must not store the request or response at all. No caching, no storage, period.


    Cache-Control: no-store


    When to use it:


    Use no-store for sensitive content: financial data, private user information, authentication tokens. If storage itself must be avoided, no-store is the right directive.


    Not a privacy guarantee:


    no-store is a request to well-behaved caches. Malicious or misconfigured caches might ignore it. Always combine with HTTPS and proper authentication for real privacy. From RFC 9111:


    > The no-store directive is not a reliable mechanism for ensuring privacy or security.


    Trade-offs:


    Every request fetches the full response from the origin — no bandwidth savings, no back/forward cache benefits. Use no-store only when necessary.


    Related: HTTP vs HTTPS: What Actually Changes covers security and caching headers.


    5. stale-while-revalidate — Serve Stale While Updating


    What it does:


    stale-while-revalidate allows caches to serve a stale (expired) response immediately while fetching a fresh copy in the background. The value is in seconds.


    Cache-Control: max-age=3600, stale-while-revalidate=86400


    This means:


  • Fresh for **3600 seconds (1 hour)**
  • After expiration, can serve stale for up to **86400 seconds (24 hours)** while revalidating in the background

  • How it works:


  • User requests a resource
  • The cached response is expired but still within the stale-while-revalidate window
  • The cache serves the stale response immediately (fast for the user)
  • The cache starts a background request to fetch a fresh copy
  • Next user gets the fresh copy

  • Why this matters:


    Users get instant responses even if the cache is stale. The next request will be fresh. This balances speed and freshness.


    CDN support varies:


    Not all CDNs support stale-while-revalidate behavior. Some CDNs that do:


  • Cloudflare (with caching rules)
  • Fastly (supports RFC 5861)
  • Some configurations of Vercel Edge Network

  • Check your CDN's documentation. Don't assume it works everywhere.


    Defined in RFC 5861.


    Related: CDN Edge Cache Explained covers how CDN caching works.


    Quick Reference


    Here's a summary of the five directives:


    | Directive | Meaning | Use Case |

    |-----------|---------|----------|

    | max-age | Fresh for N seconds (browser + CDN) | Static assets with predictable lifetime |

    | s-maxage | Fresh for N seconds (CDN only, overrides max-age) | Aggressive CDN caching, shorter browser cache |

    | no-cache | Store but revalidate before reuse | Content that must be fresh but supports 304 |

    | no-store | Do not store at all | Sensitive data (tokens, private info) |

    | stale-while-revalidate | Serve stale for N extra seconds while updating | Fast responses + background freshness |


    The Takeaway


    Cache-Control directives give you fine-grained control over how browsers and CDNs cache your content. Understanding max-age, s-maxage, no-cache, no-store, and stale-while-revalidate helps you balance speed, freshness, and security.


    The key traps to avoid:


  • `no-cache` does NOT mean "don't cache" — use `no-store` for that
  • `s-maxage` only affects shared caches (CDNs), not browsers
  • `stale-while-revalidate` behavior varies by CDN — verify support before relying on it
  • `no-store` is not a cryptographic privacy guarantee

  • For most cases, max-age with appropriate values is enough. Use the others when you need finer control.




    Related Reading:


  • [no-cache vs no-store: What's the Difference?](/blog/no-cache-vs-no-store) — deep dive into these two directives
  • [Checklist: Do You Need a CDN?](/blog/checklist-do-you-need-cdn) — understand when CDNs help
  • [What Is Caching?](/bits/what-is-caching) — caching fundamentals
  • [Browser Cache: Hard Refresh Explained](/bits/browser-cache-hard-refresh) — how to bypass browser cache
  • [HTTP Status Codes Decoded](/bits/http-status-codes) — what 304 and other codes mean



  • *This post is part of Hacking Bits, where we explain how everyday technology works — one bit at a time.*


    Related Posts