Skip to content

How to set cache headers for static files

Best practices1 min readFixes check cache-headers

Cache-Control tells browsers how long to keep a file. Long lifetimes with versioned filenames make repeat visits instant.

Step by step, with screenshots: Browser caching: what to cache, for how long, and how to set Cache-Control →

Check your own site

Runs this check and the other 192, free, in about 45 seconds.

Or run only this check with the free HTTP/2 & HTTP/3 test.

What it is

The Cache-Control header is an HTTP response header that tells browsers and CDNs whether they may store a file and for how long, for example Cache-Control: public, max-age=31536000, immutable. It is how a server says "keep this logo for a year" or "always ask me again for this page".

The directives do different jobs: max-age sets the lifetime in seconds, no-cache allows storing but requires a check with the server before each use, no-store forbids storing at all, private keeps a response out of shared caches, and immutable says the file will never change at this URL. A static file with no Cache-Control is re-downloaded on every visit or kept for a lifetime the browser guesses.

OK looks like this: versioned images, CSS, JavaScript and fonts send a long max-age with immutable, and HTML sends no-cache or a short lifetime so updates show up at once. getReport lists static files that send no cache lifetime.

What a passing site looks like

  • Static files have a cache lifetimewarning · −1.5 ptseffort S

Cache lifetime for static files

Why it matters. Without a cache lifetime, every visit downloads the same logo, CSS and scripts again. Returning visitors should get them from their browser in 0 ms.

How to fix it.
  1. Send Cache-Control: public, max-age=31536000, immutable for versioned images, CSS, JS and fonts.
  2. Most caching plugins and CDNs set this for you; check the "browser cache" or "edge TTL" setting.

Questions people ask

What is the Cache-Control header?

Cache-Control is the HTTP header that sets caching rules for a response, for browsers and for shared caches such as CDNs. It holds one or more directives, such as max-age=3600, no-cache or private, separated by commas. It replaced the older Expires and Pragma headers.

What is the difference between no-cache and no-store?

no-cache lets the browser keep a copy but makes it ask the server whether the copy is still current before using it, which is quick when nothing changed. no-store forbids keeping a copy at all, so everything is downloaded again. Use no-cache for HTML and no-store only for sensitive data.

What does Cache-Control immutable mean?

immutable tells the browser that the file at this URL will never change during its max-age, so it should not even check with the server when the visitor reloads. Use it only for versioned files whose name changes when the content changes, such as app.3f9c2.js.

What is max-age in Cache-Control?

max-age is the number of seconds a response stays fresh, counted from when it was fetched. max-age=31536000 is one year, the usual value for versioned static files; max-age=0 means the copy must be revalidated before every use. s-maxage sets a separate lifetime for CDNs.

What is the difference between Cache-Control and ETag?

Cache-Control decides how long a stored copy can be used without asking the server. ETag is a version tag the server sends with a file, so that when the copy expires the browser can ask "has it changed?" and get a tiny 304 Not Modified answer instead of the full file. They work together.

Filed under Best practices. Copy is generated from the same catalogue that scores every report, so what you read here is what the report says.