Skip to content

How to Configure Cache Headers for Your Site

Key idea:

Cache-Control is an HTTP header controlling browser and CDN caching. For immutable assets (JS/CSS/images with hash) — public, max-age=31536000, immutable (1 year). For HTML — public, max-age=60, stale-while-revalidate=86400. For APIs — no-store. Correct config speeds up repeat visits by 30-80%.

Below: step-by-step, working examples, common pitfalls, FAQ.

Step-by-Step Setup

  1. Identify resource type: immutable asset (hashed name) / HTML / API / user data
  2. For immutable (app.a8f3c.js): Cache-Control: public, max-age=31536000, immutable
  3. For HTML homepage: Cache-Control: public, max-age=60, s-maxage=600
  4. For APIs: Cache-Control: no-store (personal data) or private, max-age=0, must-revalidate
  5. Add ETag or Last-Modified for conditional requests (304 Not Modified)
  6. Verify with Enterno HTTP Checker — shows all response headers
  7. In DevTools → Network → inspect size and "(from cache)" / "(disk cache)" / "(memory cache)"

Working Examples

ScenarioConfig / Record
nginx: static with hash (1 year)location ~* \.(js|css|png|jpg|woff2)$ { add_header Cache-Control "public, max-age=31536000, immutable"; }
nginx: HTML (short cache)location / { add_header Cache-Control "public, max-age=60, s-maxage=600"; }
Apache: .htaccess static<FilesMatch "\.(js|css|png|jpg|woff2)$"> Header set Cache-Control "public, max-age=31536000, immutable" </FilesMatch>
API (no-cache)Cache-Control: no-store, no-cache, must-revalidate
CDN-aware (CDN caches, browser does not)Cache-Control: public, max-age=0, s-maxage=86400

Common Pitfalls

  • Caching HTML for 1 year — new posts invisible to visitors until cache clears
  • No immutable on hashed static assets — browser sends pointless If-None-Match each time
  • Cache-Control: no-cache ≠ "don't cache". It means "always revalidate". Use no-store
  • Private data in a public CDN cache = cross-user leak (critical bug)
  • Not updating cache headers after CDN purge — stale assets stick in browsers

Learn more

Frequently Asked Questions

Difference between max-age and s-maxage?

<code>max-age</code> — TTL for private caches (browser). <code>s-maxage</code> — TTL for shared caches (CDN, proxy). If both are set — each cache uses its own.

What is immutable?

A Cache-Control directive: "this resource will never change". The browser skips revalidation (If-None-Match) even on reload. Important for hash-based assets.

Do I need ETag if I have Cache-Control?

Yes. Cache-Control says "cache is valid for N seconds". ETag is used at expiry for 304 Not Modified (conditional requests). They complement each other.

How do I inspect my site's cache strategy?

<a href="/en/check">Enterno HTTP Checker</a> → enter URL → Cache section shows Cache-Control, ETag, Age, max-age.