Caching makes sites faster and cheaper, but it can also show people stale data. Learn the layers of a cache, how Cache-Control works, and how to avoid the classic mistakes.
A cache is a saved copy of something that is expensive to produce, kept somewhere closer or quicker to reach. Done well, caching makes pages load instantly and cuts your server costs. Done badly, it shows visitors yesterday’s prices.
The trick is knowing which layer to use for which kind of content.
The layers of a cache
A single request can pass through several caches. Each one can answer without bothering the next.
Controlling the browser and CDN with headers
Your server tells browsers and CDNs how to cache a response using the Cache-Control header.
Cache-Control: public, max-age=31536000, immutable| Directive | What it means |
|---|---|
max-age=N | Treat the response as fresh for N seconds |
public | Any cache, including a CDN, may store it |
private | Only the visitor’s own browser may store it. Use for personal data |
no-cache | May be stored, but must be checked with the server before each use |
no-store | Do not store it at all. Use for sensitive responses |
immutable | The file will never change at this URL, so do not even recheck |
stale-while-revalidate=N | Serve the old copy for a while, and refresh it in the background |
A strategy that works for most sites
Different content deserves different rules:
| Content | Suggested approach |
|---|---|
| CSS, JavaScript and images with a hash in the file name | Cache for a year with immutable. A new build gets a new file name |
| HTML pages | Short cache or no-cache with validation, so updates appear quickly |
| Public API data that changes slowly | Cache for seconds or minutes, or use stale-while-revalidate |
| User specific or sensitive data | private or no-store |
The “hash in the file name” trick, such as app.3f9a1c.js, solves the hardest part. Because the name changes whenever the content changes, you can cache the old name forever and never serve stale files.
Validation: checking without downloading
When a cached copy expires, the browser does not have to download everything again. It can ask, “has this changed?” using an ETag, a fingerprint of the content. If nothing changed, the server replies 304 Not Modified with no body, which is tiny and quick.
The hard part: invalidation
Knowing when to throw a cached copy away is famously difficult. Some practical guidance:
- Prefer expiry over manual purging. A short time to live (TTL) fixes itself.
- Version your URLs for files that change, instead of purging.
- Be careful with personal data. Never let a shared cache store one user’s private response.
- Test with the network tab. Check headers and the “from cache” labels in your browser’s developer tools.