Skip to main content
MintSaaS
Performance•6 min read

Browser Caching: How to Set Cache Headers Correctly in 2027

To set up browser caching, configure `Cache-Control` headers on your server/CDN. Use `max-age=31536000, immutable` for versioned static assets (CSS, JS, images), `max-age=3600, must-revalidate` for HTML pages, and `no-store` for sensitive/dynamic ...

M
MintSaaS Engineering Group
November 4, 2026
Share:
Browser Caching: How to Set Cache Headers Correctly in 2027

Browser Caching: How to Set Cache Headers Correctly in 2027

Quick answer: To set up browser caching, configure Cache-Control headers on your server/CDN. Use max-age=31536000, immutable for versioned static assets (CSS, JS, images), max-age=3600, must-revalidate for HTML pages, and no-store for sensitive/dynamic content. Add ETag or Last-Modified for conditional requests. Use stale-while-revalidate for background updates. Proper caching reduces repeat-visit load times by 50-90%.[1][3][4]

Browser caching is one of the simplest yet most effective performance optimizations. By storing static assets locally, repeat visits load instantly without re-downloading resources. Yet many sites misconfigure cache headers, either caching too little (slow repeat visits) or too much (stale content).

Cache-Control header

The Cache-Control HTTP header controls how browsers and CDNs cache responses.

Directives

DirectiveMeaningUse case
max-age=NCache for N secondsAll cacheable content
s-maxage=NCDN cache for N seconds (overrides max-age for shared caches)CDN-specific caching
publicAny cache can store (browser + CDN)Static assets
privateOnly browser can cache (not CDN)User-specific content
no-cacheMust revalidate before using cached copyFrequently updated content
no-storeDon't cache at allSensitive data
must-revalidateMust revalidate when expiredHTML pages
immutableContent never changes (skip revalidation)Versioned assets
stale-while-revalidate=NServe stale while fetching fresh in backgroundNon-critical updates

Caching strategies by content type

Static assets (CSS, JS, images, fonts)

Cache-Control: public, max-age=31536000, immutable
  • Cache for 1 year (max recommended)
  • immutable tells browser not to revalidate (file won't change)
  • Use content hashing in filenames: styles.a3f2b1.css
  • When content changes, filename changes, so old cache is irrelevant[3]

HTML pages

Cache-Control: public, max-age=3600, must-revalidate
  • Cache for 1 hour
  • must-revalidate forces revalidation when expired
  • Or use stale-while-revalidate for better UX:
Cache-Control: public, max-age=3600, stale-while-revalidate=86400
  • Serve stale content for up to 24 hours while fetching fresh in background[3]

API responses

Cache-Control: public, max-age=300, s-maxage=600
  • Browser caches for 5 minutes
  • CDN caches for 10 minutes
  • Use Vary: Accept-Encoding for content negotiation[3]

Sensitive content (user data, auth pages)

Cache-Control: private, no-store
  • Don't cache at all
  • Prevents shared caches (CDN) from storing user-specific data
  • Ensures fresh data on every request[3]

User-specific content (dashboards, profiles)

Cache-Control: private, max-age=300
  • Only browser caches (not CDN)
  • Short cache duration (5 minutes)
  • Revalidate on navigation[3]

Conditional requests

ETag

Server sends an ETag (entity tag) with the response:

http
ETag: "a3f2b1c4d5e6"

On subsequent requests, browser sends:

http
If-None-Match: "a3f2b1c4d5e6"

If content hasn't changed, server responds with 304 Not Modified (no body, saves bandwidth).[3]

Last-Modified

Server sends:

http
Last-Modified: Wed, 04 Nov 2026 12:00:00 GMT

Browser sends:

http
If-Modified-Since: Wed, 04 Nov 2026 12:00:00 GMT

Server responds with 304 if not modified.[3]

Recommendation: Use ETag (more precise) for static assets. Use Last-Modified for dynamic content. Don't use both (redundant).[3]

Service Worker caching

For PWAs, use Service Workers for advanced caching:

javascript
// Cache-first strategy (for static assets)
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

// Network-first strategy (for API calls)
self.addEventListener('fetch', (event) => {
  event.respondWith(
    fetch(event.request).then((response) => {
      const clone = response.clone();
      caches.open('api-cache').then((cache) => {
        cache.put(event.request, clone);
      });
      return response;
    }).catch(() => {
      return caches.match(event.request);
    })
  );
});

Strategies:

  • Cache-first: Serve from cache, fetch if not cached (static assets)
  • Network-first: Fetch from network, fall back to cache (API calls)
  • Stale-while-revalidate: Serve from cache, update in background (HTML)[3]

Common mistakes

1. No cache headers

Default behavior varies by server. Without explicit headers, browsers may cache unpredictably or not at all.[3]

2. Caching everything

Caching HTML pages for 1 year means users see stale content. Use short cache durations for dynamic content.[3]

3. Not using content hashing

Without content hashing, you can't use long cache durations for updated files. Always hash filenames for static assets.[3]

4. Ignoring Vary header

If your server returns different content based on Accept-Encoding or User-Agent, use Vary header to prevent cache confusion:

Vary: Accept-Encoding

5. Caching authenticated responses

Never cache responses that contain user-specific data with public. Use private or no-store.[3]

Measuring cache effectiveness

Chrome DevTools

  • Network tab: Check "Size" column (should show "(disk cache)" or "(memory cache)" for cached resources)
  • Application tab: View cached resources in "Cache Storage" and "Service Workers"[3]

Lighthouse

  • "Serve static assets with an efficient cache policy" audit
  • Flags resources with cache duration < 1 year[4]

WebPageTest

  • Shows cache hit/miss for each resource
  • "Repeat View" metrics show cached performance[4]

Frequently Asked Questions (FAQ)

What is browser caching?

Browser caching stores copies of web resources (images, CSS, JS) on the user's device. On repeat visits, the browser loads these from local storage instead of re-downloading, dramatically reducing load times.[3][4]

How long should I cache static assets?

1 year (max-age=31536000) for versioned static assets (with content hashing in filenames). This is the maximum recommended by Google. Use immutable to prevent revalidation.[3]

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

no-cache means the browser must revalidate with the server before using the cached copy (but can still cache). no-store means don't cache at all. Use no-store for sensitive data.[3]

What is stale-while-revalidate?

stale-while-revalidate allows serving stale (expired) content while fetching fresh content in the background. This improves perceived performance — users see content instantly while the cache updates.[3]

How do I check my cache headers?

Use Chrome DevTools Network tab (click a request → Headers tab → Response Headers). Or use curl: curl -I https://example.com/style.css. Look for Cache-Control header.[3]

Should I use ETag or Last-Modified?

Use ETag for static assets (more precise). Use Last-Modified for dynamic content. Don't use both — they're redundant and can cause conflicts.[3]

How does caching affect Core Web Vitals?

Caching improves LCP (cached CSS/JS loads faster), FCP (cached resources render quicker), and reduces server load (lower TTFB). Repeat visits can be 50-90% faster with proper caching.[3][4]

What is a Service Worker?

A Service Worker is a JavaScript file that runs in the background and can intercept network requests. It enables advanced caching strategies (cache-first, network-first, stale-while-revalidate) and offline support for PWAs.[3]

Related reading on MintSaaS

Sources

[1] MDN Web Docs — HTTP Caching: https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching

[2] Web.dev — HTTP cache: https://web.dev/articles/http-cache

[3] MintSaaS Image Compressor: https://www.mintsaas.net/products/image-compressor

[4] Web.dev — Core Web Vitals: https://web.dev/vitals/

[5] MintSaaS PDF Compressor: https://www.mintsaas.net/products/pdf-compressor

Free tools on MintSaaS

Try our free tools to put this guide into practice:

Editorial Transparency & AI Disclosure

MintSaaS Dispatch articles are researched and synthesized with the assistance of artificial intelligence analysis, then edited, verified, and benchmarked by our engineering editorial team. Customer personal data and platform source files are strictly segregated and are never used to train or fine-tune public artificial intelligence models.

Related Tags
#browser caching set cache#Performance#browser#caching#cache#headers#correctly#SaaS#productivity#automation#remote work#customer journey#onboarding