How to Set Up Browser Caching for Speed and SEO
Moderate 13 min 2026-03-20

How to Set Up Browser Caching for Speed and SEO

Quick Summary

  • What this covers: Browser caching stores static files locally so repeat visitors load pages instantly. Configure cache headers to reduce server load and improve Core Web Vitals.
  • Who it's for: site owners and SEO practitioners
  • Key takeaway: Read the first section for the core framework, then use the specific tactics that match your situation.

Browser caching stores static files (images, CSS, JavaScript) in the visitor's browser so they don't need to be re-downloaded on subsequent visits. Without browser caching, every page load requests the same files from the server, wasting bandwidth and slowing down load times. With caching enabled, repeat visitors see near-instant page loads.

Google's PageSpeed Insights flags sites without browser caching with "Leverage browser caching" or "Serve static assets with an efficient cache policy" warnings. Fixing this improves Core Web Vitals scores, reduces server load, and enhances user experience.

This guide shows how to implement browser caching on Apache, Nginx, WordPress, and Shopify, and how to set optimal cache expiration times for different file types.

How Browser Caching Works

When a user visits your site for the first time:

  1. Browser requests files (HTML, CSS, JS, images)
  2. Server sends files with cache-control headers specifying how long to store them
  3. Browser stores files locally
  4. On subsequent visits, browser checks if cached files are still valid
  5. If valid, browser loads files from cache instead of requesting them from the server

Cache-Control Headers

The Cache-Control header tells browsers how long to cache a file.

Example:

Cache-Control: max-age=31536000

This tells the browser to cache the file for 31,536,000 seconds (1 year).

Expires Headers

The Expires header sets an absolute expiration date.

Example:

Expires: Thu, 31 Dec 2026 23:59:59 GMT

Best practice: Use Cache-Control (more flexible) instead of Expires.

Optimal Cache Durations by File Type

File Type Recommended Cache Duration Reason
Images (JPG, PNG, WebP) 1 year (31536000 seconds) Images rarely change
CSS files 1 year CSS changes infrequently; use versioning to bust cache
JavaScript files 1 year JS changes infrequently; use versioning
Fonts (WOFF, WOFF2) 1 year Fonts are static
HTML pages 0 seconds or very short (e.g., 3600 = 1 hour) HTML changes frequently (content updates)
PDFs, documents 1 month (2592000 seconds) Moderate change frequency

Rule: Cache static assets aggressively (1 year). Cache dynamic content conservatively (no cache or short cache).

How to Set Up Browser Caching

Apache (.htaccess)

Add this code to your .htaccess file:

<IfModule mod_expires.c>
  ExpiresActive On

  # Images
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/gif "access plus 1 year"
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType image/x-icon "access plus 1 year"

  # CSS and JavaScript
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType application/x-javascript "access plus 1 year"

  # Fonts
  ExpiresByType font/woff "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
  ExpiresByType application/font-woff "access plus 1 year"
  ExpiresByType application/font-woff2 "access plus 1 year"

  # HTML (no cache or short cache)
  ExpiresByType text/html "access plus 0 seconds"

  # PDF and documents
  ExpiresByType application/pdf "access plus 1 month"
</IfModule>

# Alternative: Cache-Control headers
<IfModule mod_headers.c>
  <FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
    Header set Cache-Control "max-age=31536000, public"
  </FilesMatch>

  <FilesMatch "\.(css|js)$">
    Header set Cache-Control "max-age=31536000, public"
  </FilesMatch>

  <FilesMatch "\.(woff|woff2|ttf|eot)$">
    Header set Cache-Control "max-age=31536000, public"
  </FilesMatch>

  <FilesMatch "\.(html|htm)$">
    Header set Cache-Control "max-age=0, no-cache, must-revalidate"
  </FilesMatch>
</IfModule>

How to apply:

  1. Access your site via FTP or file manager
  2. Open .htaccess file (usually in the root directory)
  3. Add the code above
  4. Save and test

Nginx (nginx.conf)

Add this to your server block in nginx.conf:

location ~* \.(jpg|jpeg|png|gif|webp|svg|ico|pdf)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

location ~* \.(css|js)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

location ~* \.(woff|woff2|ttf|eot)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

location ~* \.(html|htm)$ {
  expires 0;
  add_header Cache-Control "no-cache, must-revalidate";
}

How to apply:

  1. SSH into your server
  2. Open nginx config: sudo nano /etc/nginx/nginx.conf
  3. Add the code above inside the server { } block
  4. Test config: sudo nginx -t
  5. Reload nginx: sudo systemctl reload nginx

WordPress (with Plugin)

WP Rocket and W3 Total Cache automatically set browser caching headers.

WP Rocket:

  1. Install and activate WP Rocket
  2. Go to Settings > WP Rocket > File Optimization
  3. Browser caching is enabled by default

W3 Total Cache:

  1. Install and activate W3 Total Cache
  2. Go to Performance > Browser Cache
  3. Enable Set expires header
  4. Set lifespans for CSS, JS, HTML, and media files

WordPress (Manual via .htaccess)

If you're not using a caching plugin, add the Apache code above to your .htaccess file.

Shopify

Shopify automatically sets browser caching for all assets. You don't need to configure anything.

To verify Shopify is caching assets, check response headers using browser DevTools:

  1. Open a page on your Shopify site
  2. Open Chrome DevTools (F12)
  3. Go to Network tab
  4. Reload the page
  5. Click on an image or CSS file
  6. Check Headers for Cache-Control or Expires

Shopify typically sets Cache-Control: max-age=31536000 for static assets.

How to Verify Browser Caching Is Working

Method 1: Google PageSpeed Insights

  1. Go to https://pagespeed.web.dev/
  2. Enter your URL
  3. Run the test
  4. Check "Diagnostics" section for "Serve static assets with an efficient cache policy"

If this warning appears, your caching headers aren't set correctly.

Method 2: Check Response Headers Manually

Using Chrome DevTools:

  1. Open your site
  2. Press F12 to open DevTools
  3. Go to Network tab
  4. Reload the page
  5. Click on a CSS, JS, or image file
  6. Check Headers section for Cache-Control or Expires

Expected result:

Cache-Control: max-age=31536000

Using curl:

curl -I https://yoursite.com/style.css

Look for Cache-Control or Expires headers in the response.

Method 3: GTmetrix

  1. Go to https://gtmetrix.com/
  2. Enter your URL
  3. Run the test
  4. Go to PageSpeed tab
  5. Check for "Leverage browser caching" recommendation

If this appears, caching isn't configured.

Cache Busting (Handling File Updates)

If you cache files for 1 year, how do browsers get updates when you change CSS or JS?

Solution: Cache busting via versioning.

Method 1: Query String Versioning

Append a version number to file URLs:

<link rel="stylesheet" href="/style.css?v=1.2">
<script src="/script.js?v=1.2"></script>

When you update the file, increment the version:

<link rel="stylesheet" href="/style.css?v=1.3">

Browsers see this as a new file and request it from the server.

Method 2: File Name Versioning

Rename files when they change:

<link rel="stylesheet" href="/style-v1.2.css">

Update to:

<link rel="stylesheet" href="/style-v1.3.css">

This is more reliable than query string versioning (some proxies ignore query strings).

Method 3: Automated Build Tools

Build tools (Webpack, Gulp, Parcel) automatically append content hashes to filenames:

<link rel="stylesheet" href="/style.a3f8c12.css">

When the file content changes, the hash changes, busting the cache automatically.

Common Browser Caching Mistakes

Mistake 1: Caching HTML Pages for Too Long

If you cache HTML for 1 year, users won't see content updates until the cache expires.

Fix: Set HTML cache to 0 or a short duration (e.g., 1 hour).

Mistake 2: Not Cache Busting After Updates

You update style.css but it's cached for 1 year. Users see the old version.

Fix: Implement versioning (query strings or file renaming).

Mistake 3: Caching Dynamic Content

Don't cache pages that change per user (cart pages, account pages, search results).

Fix: Exclude dynamic pages from caching:

Apache (.htaccess):

<FilesMatch "(cart|checkout|my-account)">
  Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>

Nginx:

location ~ (cart|checkout|my-account) {
  add_header Cache-Control "no-cache, must-revalidate";
}

Mistake 4: Setting Cache-Control and Expires Differently

Don't set conflicting headers:

Cache-Control: max-age=31536000
Expires: Thu, 01 Jan 2025 00:00:00 GMT

If these don't align, browsers may behave unpredictably.

Fix: Use Cache-Control only. It's more flexible and widely supported.

Mistake 5: Not Testing After Implementation

Implement caching headers but don't verify they're working. Test with PageSpeed Insights and browser DevTools.

Browser Caching and CDNs

CDNs (Content Delivery Networks) cache files on edge servers globally. Combining browser caching with a CDN maximizes performance:

  1. Browser caching reduces requests to your server for repeat visitors
  2. CDN caching reduces latency for first-time visitors by serving files from nearby edge servers

Recommended CDNs:

Frequently Asked Questions

What's the difference between browser caching and server-side caching?

Browser caching stores files in the visitor's browser. Server-side caching (e.g., page caching, object caching) stores files on the server to reduce processing time. Both improve speed but serve different purposes.

Can I cache for longer than 1 year?

Yes, but 1 year is the practical maximum. Most browsers and CDNs use 1 year as the standard.

Will browser caching break my site if I update files?

Only if you don't implement cache busting. Use versioning (query strings or file renaming) to force browsers to request updated files.

How do I clear cached files for all users?

You can't force users to clear their cache. Use cache busting (versioning) to bypass cached versions.

Does browser caching improve SEO?

Indirectly. Browser caching improves page speed, which improves Core Web Vitals, which is a ranking factor. Faster pages also reduce bounce rate and improve user engagement.

Next Steps

Implement browser caching using the appropriate method for your platform (Apache, Nginx, WordPress plugin). Test with Google PageSpeed Insights to verify the "Leverage browser caching" warning is resolved. Implement cache busting via versioning for CSS and JS files. For additional speed optimization, see Best WordPress Caching Plugins Compared, Server-Side Caching Explained, and Fix Leverage Browser Caching Warning.


When This Fix Isn't Your Priority

Skip this for now if:

This is one piece of the system.

Built by Victor Romo (@b2bvic) — I build AI memory systems for businesses.

← All Fixes