Caching

Cache-Control

Set freshness and storage rules with max-age, public, private, no-cache, no-store, and immutable response directives.

Cache-Control is the main header caches read. It holds one or more directives that say who may store a response and for how long.

A typical public asset might look like this:

Cache-Control: public, max-age=3600

Shared caches (CDNs, corporate proxies) may store this response. It stays fresh for 3600 seconds, one hour, before a cache must revalidate or refetch.

Check a live response:

curl -I https://flaviocopes.com/img/og.png

Look for cache-control in the output. Static images on production sites often carry long max-age values because the file path includes a content hash or rarely changes.

Useful directives include:

  • private: only a browser’s private cache should store it.
  • no-store: do not store the response anywhere.
  • no-cache: storage is allowed, but the cache must validate before reuse.
  • max-age=60: fresh for 60 seconds.
  • immutable: the URL’s content will not change while fresh.

no-cache is often misunderstood. It does not mean “do not cache.” It means “you may store it, but check with the origin before serving it again.” That check usually involves an ETag or Last-Modified validator.

Versioned assets such as /app.a1b2.css can use a long lifetime plus immutable. When the file changes, its URL changes too, so browsers keep the old copy without asking. Personalized account pages usually need private or no-store, because no shared cache should hold user-specific HTML.

Be careful mixing public with session cookies. If the response body includes private data and Cache-Control: public, a CDN might serve your dashboard to another visitor. I always audit cache headers after adding auth to a route.

Try this: pick a CSS file from your site’s Network panel and read its Cache-Control. Compare it with the main HTML document. The difference explains why CSS loads instantly on repeat visits while HTML may always hit the network.

Lesson completed