---
title: "What is Cache-Control? Every directive that matters, explained — warmup.rocks Glossary"
description: "Cache-Control tells browsers and CDNs whether and how long to cache a response. max-age, s-maxage, no-cache vs. no-store, public vs. private, immutable and stale-while-revalidate — what each directive does."
canonical: https://warmup.rocks/glossary/cache-control
---

# Cache-Control

**Cache-Control** is the HTTP header that governs caching: whether a response may be stored, by whom (browser only, or shared caches like CDNs too), for how long, and what happens when it goes stale. If you configure exactly one header on your site, make it this one.

## The directives that matter

| Directive | What it does |
| --- | --- |
| `max-age=3600` | Fresh for 3600 s — applies to browsers _and_ shared caches. |
| `s-maxage=86400` | Overrides `max-age` for shared caches (CDNs) only — see [s-maxage](https://warmup.rocks/glossary/s-maxage). |
| `public` | May be stored by any cache, even when other signals suggest otherwise. |
| `private` | Browser may cache it; CDNs must not. For personalized responses. |
| `no-cache` | May be stored, but must be revalidated (e.g. via [ETag](https://warmup.rocks/glossary/etag)) before every use. _Not_ "don't cache". |
| `no-store` | The actual "don't cache": nothing may be written to any cache. |
| `immutable` | Won't change during its lifetime — browsers skip revalidation on reload. For fingerprinted assets. |
| `stale-while-revalidate=60` | Serve stale for up to 60 s while refreshing in the background — see [stale-while-revalidate](https://warmup.rocks/glossary/stale-while-revalidate). |

## A pattern that covers most sites

```
# HTML — short in the browser, long at the edge, purge + warm on deploy
Cache-Control: public, max-age=60, s-maxage=86400

# Fingerprinted assets (app.3f9a2c.js) — cache forever, never revalidate
Cache-Control: public, max-age=31536000, immutable
```

The split matters: browsers you can't purge, CDNs you can. A short `max-age` keeps browsers honest; a long `s-maxage` gives the CDN a high [hit ratio](https://warmup.rocks/glossary/cache-hit-ratio); a [purge](https://warmup.rocks/glossary/cache-purge) plus re-warm on deploy keeps content correct.

## What Cache-Control can't do

It sets the rules, not the reality. A CDN may cap or override your TTLs, ignore directives it doesn't support, or [evict your object early](https://warmup.rocks/glossary/cache-eviction) under cache pressure. And some CDNs need explicit opt-in before they cache HTML at all — Cloudflare famously marks HTML [DYNAMIC](https://warmup.rocks/blog/cf-cache-status) by default no matter what Cache-Control says. Verify what actually happens at the edge with our [cache checker](https://warmup.rocks/cache-checker).
