The fastest request is the one that never happens. When a visitor comes back to your site, or clicks through to a second page, their browser can reuse files it has already downloaded: your stylesheet, your logo, your fonts, your JavaScript bundles. Whether it actually does depends almost entirely on a few HTTP headers.
Browser caching is one of the oldest performance techniques on the web, yet misconfigured cache headers are still everywhere. Some sites cache nothing, forcing repeat downloads; others cache HTML so aggressively that visitors see stale prices or old navigation for days.
This guide explains how the HTTP cache works, which Cache-Control settings to use for different file types, how to set them up on common servers and CDNs, and how to test that your caching is doing what you expect.
Key Takeaways
- Browser caching lets repeat visitors reuse files instead of downloading them again, cutting load times and server load.
- Use long lifetimes, such as
max-age=31536000, only for versioned (fingerprinted) files whose URL changes when content changes. - Use
no-cache(revalidate before use) for HTML and other unversioned files; it does not mean "do not cache". - Prefer
ETagfor validation and avoid relying on browsers guessing cache lifetimes. - The back/forward cache (bfcache) is separate from the HTTP cache and is easy to block by accident.
How Browser Caching Works
When a browser requests a file, the server's response headers tell it whether the file can be stored, for how long, and how to check later whether it has changed. On the next request for the same URL, the browser looks in its HTTP cache first. If the stored copy is still "fresh", it is used immediately with no network trip. If it is "stale", the browser asks the server whether it has changed; a 304 Not Modified answer lets it reuse the stored copy.
A common myth is that leaving out cache headers disables caching. web.dev's HTTP cache guide points out the opposite: omitting Cache-Control does not disable HTTP caching, and browsers effectively guess a lifetime instead. Guessing is not a strategy, so set headers explicitly.
Cache-Control Directives Explained
| Directive | What it means | Typical use |
|---|---|---|
max-age=N | The response is fresh for N seconds | Static assets |
immutable | The file will not change during its lifetime, so skip revalidation (ignored by some browsers) | Fingerprinted CSS/JS/fonts |
no-cache | Store it, but revalidate with the server before every use | HTML pages |
no-store | Never store any version, in the browser or in CDNs | Sensitive, personalised responses |
private | Browser may cache; shared caches such as CDNs may not | Logged-in pages |
public | Any cache may store the response | Public static files |
“This instructs the browser that it must revalidate with the server every time before using a cached version of the URL.”
— web.dev, describing no-cache, Prevent unnecessary network requests with the HTTP Cache
Validation: ETag and Last-Modified
Revalidation needs something to compare. An ETag is a token (usually a hash of the file contents) that the browser sends back in an If-None-Match header. Last-Modified uses a timestamp instead. web.dev recommends ETag because it is more accurate. Note that revalidation still costs a round trip, even if the 304 response is tiny, which is why long lifetimes on versioned assets matter so much.
A Practical Caching Strategy by File Type
The pattern used by most high-performance sites is simple: give every static asset a unique, versioned URL (for example app.3f9a1c.js), cache those for a year, and keep HTML short-lived so it can point to new versions instantly.
| File type | Recommended header | Why |
|---|---|---|
| HTML documents | Cache-Control: no-cache (or a short max-age) | Content changes; users must see updates |
| Versioned CSS and JS | Cache-Control: public, max-age=31536000, immutable | URL changes whenever content changes |
| Web fonts (versioned) | public, max-age=31536000, immutable | Fonts rarely change; see web font optimization |
| Images with versioned URLs | public, max-age=31536000 | Large files, big savings on repeat views |
| Unversioned images or logos | A few days to weeks, with ETag | Balance freshness and reuse |
| Account, cart and checkout pages | private, no-cache or no-store | Personal or sensitive data |
robots.txt and sitemaps | Short lifetime | Changes should be picked up quickly |
How to Set Up Browser Caching (Step by Step)
- Check your current headers. In Chrome DevTools, open the Network tab, click a file and read the Response Headers, or run
curl -I https://example.com/style.css. - Turn on asset fingerprinting. Most build tools (Vite, webpack and many CMS optimisation plugins) can add a content hash to file names.
- Configure long-lived headers for fingerprinted assets. On Apache, use
mod_headersormod_expiresin.htaccess; on Nginx, add anexpiresoradd_header Cache-Controlrule for asset paths. - Set HTML to revalidate. Use
no-cacheor a short max-age so updates appear immediately. - Align your CDN. Make sure the CDN respects or overrides origin headers deliberately, and purge it on deploys. If your origin is hard to change, headers can also be set at the CDN layer, as explained in our guide to edge SEO. Our CDN SEO guide covers this layer.
- Protect private pages with
privateorno-store. - Test a repeat visit. Reload the page and confirm static assets show "(memory cache)" or "(disk cache)" in DevTools.
- Re-run a Lighthouse report. Since Lighthouse 13, the old long-cache audit appears as a "use efficient cache lifetimes" insight; see our Lighthouse audit guide.
Apache example
<FilesMatch "\.(css|js|woff2|webp|avif)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
<FilesMatch "\.html$">
Header set Cache-Control "no-cache"
</FilesMatch>
Only use the one-year rule if those files are fingerprinted. If your CSS is always called style.css, a year-long cache will trap users on old styles. If you edit .htaccess regularly, our guide to .htaccess redirects covers safe editing habits.
Don't Forget the Back/Forward Cache
The back/forward cache (bfcache) is a different mechanism: web.dev describes it as a snapshot of the entire page in memory, which makes back and forward navigation instant. It is easy to block without realising.
“The most important way to optimize for bfcache in all browsers is to never use the unload event.”
— web.dev, Back/forward cache
web.dev also notes that pages served with Cache-Control: no-store have historically been excluded from bfcache by browsers, which is another reason to reserve no-store for truly sensitive pages.
Does Browser Caching Help SEO?
Caching mainly benefits returning visitors and multi-page journeys, which shows up in real-user Core Web Vitals data rather than in a single lab test. Faster repeat views support the user experience signals described in our Core Web Vitals guide. Googlebot has its own caching behaviour, but sensible headers and stable resource URLs also help keep crawling efficient, as explained in our crawl budget guide.
Common Mistakes
- Long lifetimes on unversioned files, so users keep seeing old CSS or JavaScript after a release.
- Caching HTML for hours or days, leading to stale prices, stock levels or menus.
- Thinking
no-cachemeans "never cache". That isno-store. - Using
no-storeeverywhere, which forces full re-downloads and can block bfcache. - Letting the CDN and origin disagree, so debugging becomes guesswork.
- Caching error pages. A cached 5xx response can turn a short outage into a long one; see our guide to 5xx server errors.
Related Guides
- Index Bloat: How to Find and Remove Low-Value Indexed Pages
- How to Keep Staging Sites Out of Google
- Search Console Crawl Stats Report: How to Read It
Frequently Asked Questions
What is a good max-age for static files?
For fingerprinted files whose URL changes with every update, one year (max-age=31536000) is the widely recommended value. For unversioned files, use a much shorter lifetime with ETag validation.
What is the difference between no-cache and no-store?
no-cache lets the browser store the file but requires it to check with the server before reuse. no-store forbids storing the response anywhere.
Does browser caching improve Core Web Vitals?
It can improve real-user metrics for repeat visits and multi-page sessions because fewer resources need downloading. It does not change the first visit.
How do I clear users' cached files after an update?
You cannot reliably clear a visitor's cache remotely. Instead, change the file name or add a version hash so the HTML points to a new URL.
Is browser caching the same as a caching plugin?
Not exactly. Many WordPress caching plugins mainly create cached HTML on the server, and some also set browser cache headers. Check the actual response headers to see what is happening.
Conclusion
Good browser caching follows one rule: cache versioned assets for a very long time and keep HTML fresh. Add explicit headers, fingerprint your files, keep no-store for sensitive pages and check the bfcache, and repeat visitors will feel the difference.
If you would like experts to configure caching, CDN and server settings together, our page speed optimization service can help. Request a free quote today.




