# Cache-Control and Friends — Caching Strategies & CDN Design

Source: https://www.skillbyai.com/en/caching-strategies/h-headers

> Write Cache-Control headers that tell browsers and CDNs exactly what to do.

## Caching instructions travel with the response

HTTP caching is controlled mainly by the **`Cache-Control`** response header (standardised in RFC 9111). **`max-age=N`** says the response is fresh for N seconds. **`s-maxage=N`** overrides max-age for **shared caches** such as CDNs and proxies, so you can cache longer at the edge than in browsers. **`public`** allows shared caches to store the response; **`private`** restricts storage to the user's browser, essential for personalised pages. **`no-cache`** does **not** mean "do not cache": it means caches may store the response but must **revalidate** with the server before using it. **`no-store`** means do not store it anywhere, for sensitive data. **`immutable`** tells browsers the content will never change during its freshness lifetime, so they skip revalidation even on reload. **`must-revalidate`** forbids serving stale content after expiry. The older `Expires` header is superseded by `max-age`.

## Fresh, stale and revalidated

A response is fresh until max-age passes; after that it is stale and must be revalidated or refetched.

![A timeline with a bright segment, then a fading segment, and a looping arrow back to the server at the boundary.](assets/figures/caching-strategies/section-6-map.svg) — Figure 6.1 — Freshness lifetime and revalidation.

## Headers for common response types

Each line pairs a kind of content with a suitable policy.

```http
# fingerprinted static asset: app.3f9a1c.js (name changes when content changes)
Cache-Control: public, max-age=31536000, immutable

# HTML page shared by all users: short in browsers, longer at the CDN
Cache-Control: public, max-age=60, s-maxage=300

# personalised dashboard: browser only, always revalidate
Cache-Control: private, no-cache

# bank statement or one-time token: never store
Cache-Control: no-store

# public API listing that can be a little stale
Cache-Control: public, max-age=30, stale-while-revalidate=120
```

## no-cache is not no-store

Using `no-cache` for sensitive data still lets caches store it. If data must never be written to any cache, including the browser's disk, use `no-store`.

**Quiz:** Which directive lets a CDN cache a response for longer than browsers do?

- [ ] private
- [ ] no-store
- [x] s-maxage
- [ ] must-revalidate

*Answer:* s-maxage. s-maxage applies to shared caches and overrides max-age there.
