Chrome Browser Caching Guide

Why caching matters

Latency, bandwidth, resilience, and user experience gains from not hitting the network unnecessarily.

Conceptual

Browser caching in Chrome stores copies of network resources to improve performance, reduce latency, and decrease bandwidth usage. It enables offline support and smoother UX by serving assets locally instead of redownloading them.

  • Performance: Faster page loads and less jank once core assets are cached.
  • Cost: Reduced bandwidth on both client and server.
  • Reliability: Pages can keep working even on flaky or offline connections.

HTTP caching basics

Control freshness, storage, and who is allowed to cache with response headers.

Headers
Header Effect
Cache-Control: max-age=SECONDS Specifies how long a resource remains fresh in cache before it must be revalidated.
Cache-Control: no-cache Requires validation with the server before reuse even if stored.
Cache-Control: no-store Instructs the browser not to store the response at all.
Cache-Control: public / private Determines if responses can be cached by intermediaries or only locally.

Types of caches in Chrome

Multiple layers cooperate: memory, disk, page snapshots, and programmable caches.

HTTP cache SW cache
  • Memory cache: Fastest, holds recently used assets for quick reuse while the tab lives.
  • Disk HTTP cache: Stores resources on disk based on cache headers and eviction policies.
  • Back/Forward cache: Keeps entire page state for instant back/forward navigation.
  • Service worker cache: Cache Storage API lets you programmatically store and serve responses.

Chrome DevTools & cache inspection

See exactly what was cached, when, and why it was (or wasn’t) reused.

DevTools

Open DevTools with Ctrl+Shift+I (Windows/Linux) or Cmd+Opt+I (Mac). Key areas:

  • Network panel: View cache hits/misses, status codes, and response headers.
  • Application → Cache Storage: Inspect service worker caches, entries, and payloads.
  • Reload menu: Right‑click the reload icon to use “Empty Cache and Hard Reload” when testing.

Programmatic caching with service workers

Install‑time precaching plus fetch‑time routing give you full control over responses.

Service worker Cache Storage API
// Register service worker
navigator.serviceWorker.register('/sw.js');

// Inside sw.js
self.addEventListener('install', evt => {
  evt.waitUntil(
    caches.open('static-v1').then(cache => cache.addAll([
      '/', '/style.css', '/app.js'
    ]))
  );
});

self.addEventListener('fetch', evt => {
  evt.respondWith(
    caches.match(evt.request).then(resp => resp || fetch(evt.request))
  );
});

This pattern precaches core assets during install so subsequent requests can be served instantly from cache, falling back to the network when needed.

Chrome URLs for cache debugging

Built‑in diagnostic pages that reveal what Chrome is storing under the hood.

chrome://
chrome:// URL Purpose
chrome://cache Displays cache index (list of cached resources).
chrome://net-internals Advanced network and cache diagnostics.
chrome://serviceworker-internals Lists registered service workers and cache details.

Cache invalidation strategies

How to ship new code without serving stale files forever.

Versioning

Cache invalidation ensures users receive updated content when files change. Common patterns:

  • Filename versioning (recommended):
    app.v1.js → app.v2.js
    New filenames mean the browser treats the asset as fresh without needing heuristics.
  • Query string versioning:
    /app.js?v=123
    Works, but some CDNs and proxies treat query strings differently from path changes.
  • Cache-Control revalidation:
    Cache-Control: must-revalidate
    Forces the browser to check with the origin when a resource is stale.

How Chrome decides what to cache

A high‑level decision tree for each request.

Diagram
Request
  ↓
Is resource cacheable?
  ↓  (no-store, private data, etc.)
Yes
  ↓
Is it still fresh? (max-age / Expires)
  ↓
Fresh           Stale
  ↓             ↓
Serve from  Revalidate with ETag /
  cache     Last-Modified
                ↓
          304 Not Modified? ── Yes ─→ Serve cached copy
                │
                No
                ↓
        Fetch from network → Update cache → Serve new response

ETag & Last‑Modified examples

Conditional requests let Chrome reuse bytes without refetching everything.

304 flow

ETag example

ETag: "abc123"

Next request from the browser:

If-None-Match: "abc123"

If unchanged, the server returns:

304 Not Modified

Last‑Modified example

Last-Modified: Tue, 05 Jan 2026 10:00:00 GMT

Browser sends:

If-Modified-Since: Tue, 05 Jan 2026 10:00:00 GMT

Cache Storage vs IndexedDB vs LocalStorage

Picking the right storage layer for assets, structured data, and small flags.

Storage APIs
Storage type Best for Limits
Cache Storage API Storing HTTP responses and offline assets. Opaque responses count strongly toward origin quota.
IndexedDB Structured data, large datasets, search indexes. Async API and more complex data modeling.
LocalStorage Small key/value flags and user prefs. Small quota (~MBs), synchronous (blocks main thread).

Advanced service worker caching patterns

Choose a strategy per route or asset type instead of “one size fits all”.

Strategies

Cache‑first (great for static assets):

evt.respondWith(
  caches.match(evt.request).then(cached => cached || fetch(evt.request))
);

Network‑first (for APIs that must be fresh):

evt.respondWith(
  fetch(evt.request).catch(() => caches.match(evt.request))
);

Stale‑while‑revalidate (for UX + freshness):

evt.respondWith(
  caches.match(evt.request).then(cached => {
    const fetchPromise = fetch(evt.request).then(resp => {
      caches.open('dynamic').then(cache =>
        cache.put(evt.request, resp.clone())
      );
      return resp;
    });
    return cached || fetchPromise;
  })
);

Service worker request flow

How a fetch travels through your service worker’s routing logic.

Diagram
Browser request
      ↓
Service worker intercepts
      ↓
Is request in cache?
      ├─ Yes → Return cached response
      │
      └─ No  → Fetch from network
                  ↓
             Optionally save to cache
                  ↓
             Return network response

Real‑world caching examples

Copy‑paste header patterns for common scenarios.

Snippets

Static asset caching (versioned bundle):

Cache-Control: public, max-age=31536000, immutable

API responses (validate before reuse):

Cache-Control: no-cache

Sensitive data (never stored):

Cache-Control: no-store

Chrome cache quotas & limits

Origin‑scoped storage budgets and what happens when you exceed them.

Quotas
  • Chrome allocates a fraction of disk space per origin (exact numbers vary by platform).
  • Opaque responses (e.g. cross‑origin without CORS) count more heavily toward quota.
  • Eviction generally uses “least recently used” style heuristics when space is needed.

Debugging cache issues (checklist)

Systematically rule out which cache layer is serving stale content.

Checklist
  • Enable Network → Disable cache in DevTools to bypass the HTTP cache during testing.
  • Verify response headers for Cache-Control, ETag, and Last-Modified.
  • Check the Application → Service Workers panel for old workers still controlling the page.
  • Use chrome://cache or DevTools Application panels to confirm what’s stored.
  • Compare “Hard reload”, “Empty cache and hard reload”, and normal reload behavior.

Comments

Popular posts from this blog