Pixelated Cache

The Role of Caching in Speeding Up a Website

Speed happens when the browser gets what it needs without waiting.

Caching is the practice of storing responses so future requests can be served faster. Done well, caching reduces data transfer, cuts work on your servers, and shortens round trips across the network. The browser paints content sooner, your origin stays calm during traffic spikes, and users feel the difference. This guide explains where caches live, how they work, which headers matter, and how to design a cache strategy that improves speed without breaking correctness or security.

How caching makes sites feel fast

Every request has three time sinks: compute, distance, and bandwidth. Caches attack all three.

  • Compute: Serving a cached response avoids expensive database queries and template rendering.
  • Distance: Edge caches place bytes closer to visitors, which trims latency and time to first byte.
  • Bandwidth: Reusing responses and compressing them means fewer bytes on the wire.

The user experience effect shows up in familiar metrics. TTFB drops with a warm cache. Largest Contentful Paint improves when hero images, CSS, and HTML arrive quickly. Interaction latency improves because the main thread is not stuck waiting for late assets. You still need clean markup and efficient JS, but caching buys you time on every page view.

Where caching lives in the stack

Think of caching as layers that cooperate rather than a single switch you flip.

  • Browser cache: The user’s device stores previously fetched resources. Controlled with HTTP caching headers.
  • Service worker cache: A programmable cache in modern browsers that you control with JavaScript. Great for offline and stale-while-revalidate patterns.
  • CDN or edge cache: Points of presence around the world store content close to users. Ideal for static assets and cacheable HTML.
  • Reverse proxy cache: NGINX, Varnish, or a managed platform in front of your app caches responses before they hit your origin.
  • Application and object cache: In-memory stores like Redis or Memcached hold computed fragments, query results, or whole page renders.
  • Database caches: Query caches and materialized views store work you would otherwise repeat.
  • OS and hardware caches: Kernel page cache and disk controllers reduce repeated reads.

Each layer speeds up a different part of the journey. Most sites use at least the browser plus a CDN, then add reverse proxy or object caching as they grow.

The HTTP building blocks you must know

HTTP gives you a small, powerful vocabulary to control caches. Master these first.

Cache-Control

The Cache-Control header is your main lever. Common directives include:

  • max-age=N: How long, in seconds, a response is fresh for any cache.
  • s-maxage=N: Overrides max-age for shared caches like CDNs and proxies.
  • public or private: Whether shared caches may store the response.
  • no-cache: Caches must revalidate before reuse.
  • no-store: Do not write this response to a cache at all.
  • must-revalidate: Do not serve stale content after expiry without revalidation.
  • immutable: Signals that the resource will never change at the same URL.

Use s-maxage to be aggressive at the edge while keeping browsers conservative. Use immutable on fingerprinted assets, not on HTML.

Validators: ETag and Last-Modified

Validators let caches check freshness without downloading the full payload.

  • ETag: An opaque token that changes when the content changes.
  • Last-Modified: A timestamp of when the resource last changed.

Clients send If-None-Match or If-Modified-Since with a new request. If nothing changed, the server replies 304 Not Modified, which is tiny and fast.

Vary and cache keys

Caches build a cache key from the URL plus selected request properties. The Vary header tells caches which request headers are part of that key.

  • Vary on Accept-Encoding for gzip and brotli.
  • Vary on Accept-Language only if you actually localize.
  • Avoid Vary on an uncontrolled User-Agent, which explodes the cache.
  • With client hints, Vary on DPR, Width, or Save-Data when you serve adaptive images.

Be deliberate. Every item in the cache key multiplies the number of variants a cache must store.

Stale-while-revalidate and stale-if-error

Modern caches support serving slightly stale content while they fetch a fresh copy in the background. You enable this with stale-while-revalidate=N and stale-if-error=N in Cache-Control. Users get an instant response, then the cache refreshes quietly. If your origin is down, stale-if-error lets the cache keep serving known good content instead of failing.

Surrogate headers and cache tags

Some CDNs and reverse proxies honor extra headers such as Surrogate-Control and Surrogate-Key. These let you set different TTLs for shared caches or purge groups of related objects by tag. For example, you can tag all pages that reference a product, then purge that tag when the product changes.

Types of caching and when to use each

Static asset caching

Static assets like CSS, JS, and images are the easiest wins.

  • Use content hashing in filenames, for example app.3f7c9.css. Set Cache-Control: public, max-age=31536000, immutable.
  • Serve from a CDN with HTTP/2 or HTTP/3 and TLS.
  • Preload critical CSS and fonts so the browser requests them early.
  • For fonts, add font-display: swap and consider Cache-Control: max-age=31536000 with immutable.

Avoid cache-busting query strings on assets. Prefer hashed filenames so you can set long TTLs safely and let old versions age out naturally.

HTML caching

HTML is dynamic, so treat it carefully.

  • Microcaching: Cache full HTML for a few seconds at the edge or reverse proxy. This flattens traffic spikes and protects your origin.
  • Vary on auth: Keep HTML for anonymous users cacheable. Bypass or separate cache keys when a session cookie is present.
  • Hole punching: Combine a cached page with small personalized fragments fetched client side or via ESI at the edge.
  • Revalidation: Use short s-maxage and allow revalidation to keep content fresh without high origin load.

API and JSON caching

APIs that respond to GET requests are great cache candidates.

  • Use Cache-Control and validators on idempotent endpoints.
  • Cache negative responses like 404 for a short time to cut repeated misses.
  • Key by query parameters that matter. Many CDNs support parameter whitelists for cache keys.
  • Be careful with personalized data. Mark those responses private or skip caching entirely.

Object and fragment caching

Keep expensive computations in memory for a short period.

  • Store database query results, rendered templates, or API aggregations in Redis or Memcached.
  • Use structured keys like tpl:product:123:v2.
  • Set conservative TTLs and expire keys on content changes.
  • Avoid caching objects that depend on many volatile inputs.

Fragment caching gives you most of the speed of full-page caching without sacrificing personalization.

Database and search caching

Speed reads with strategies tailored to your data store.

  • Materialize common queries into summary tables on a schedule.
  • Use read replicas for heavy read traffic.
  • Enable prepared statement caches in your driver or ORM.
  • For search, cache popular queries and page through cached result IDs.

Designing a TTL matrix

Pick TTLs based on how often things change and how sensitive they are to staleness.

  • Static assets: 1 year with immutable and hashed names.
  • Product pages: Edge s-maxage from 60 to 600 seconds, browser 0 to 60 seconds with revalidation.
  • Home and category pages: Edge 30 to 120 seconds, revalidate often.
  • APIs: Minutes for reference data, seconds for fast-moving data, no cache for private data.
  • Errors: Short stale-if-error to keep serving during brief incidents.

Write this matrix down. Consistency prevents accidental regressions when teams ship changes.

Invalidation: the hard part you can make simple

Caching is easy. Invalidation is where most teams struggle. Use these patterns.

  • Versioned assets: Change the filename when content changes. No purge required.
  • Event-based purges: On publish or update, purge the affected page and any related listings by tag or surrogate key.
  • Soft purge: Mark objects stale so the next request triggers a refresh in the background. Users get fast responses with quick convergence to fresh content.
  • Hard purge: Remove objects immediately when you must eliminate something from the cache.
  • Dependency maps: Maintain a simple map from entities to URLs that mention them. Use it to target purges.

Automate purges in your CMS or admin panel so editors never file a ticket to fix stale pages.

Correctness, safety, and privacy

Speed cannot come at the cost of correctness.

  • Authenticated responses: Treat anything with a session cookie as private. Set Cache-Control: private, no-store unless you are deliberately using a separate cache key for authenticated views.
  • Personal data: Do not cache responses that include sensitive or regulated data. Prefer server-side rendering that does not embed secrets into HTML.
  • Cache poisoning: Validate and normalize inputs, whitelist query parameters in cache keys, and be careful with Vary to avoid letting attackers generate unbounded variants.
  • Mixed content and headers: Ensure HTTPS everywhere, set Content-Type correctly, and keep Content-Encoding and Vary aligned so caches do not reuse compressed responses incorrectly.

Internationalization, devices, and images

Serving the right variant is a common reason caches miss.

  • Language: If you localize by path, such as /en/ and /fr/, you can often avoid Vary on Accept-Language. If you negotiate by header, add Vary: Accept-Language and limit supported languages to keep the variant count sane.
  • Devices: Avoid broad Vary on User-Agent. Prefer responsive design and client hints.
  • Client hints: When you serve responsive images, use Vary: Accept, DPR, Width, Save-Data as appropriate so caches store the right versions for each device class.
  • Image CDNs: Offload resizing and format conversion to an image CDN that respects cache keys and client hints.

Measuring caching so you can tune it

You cannot manage what you do not measure. Track a few signals.

  • Cache hit ratio: At your CDN and reverse proxy. Watch trends by path group, not just a global number.
  • Origin offload: Requests and bytes served from the cache versus the origin.
  • TTFB and LCP: Measure by country, device, and page type. A warm cache should lower both.
  • Headers on responses: Inspect Cache-Control, Age, ETag, and any vendor-specific CDN-Cache-Status.
  • Error budget: Count how often stale-if-error served content. If it happens often, harden the origin.

Use synthetic tests and real user monitoring. Synthetic runs find configuration mistakes. Field data proves user impact.

Practical header recipes

These examples are safe defaults you can adapt.

Immutable asset

Cache-Control: public, max-age=31536000, immutable
Content-Type: text/css; charset=utf-8

Anonymous HTML with edge revalidation

Cache-Control: public, max-age=0, s-maxage=120, stale-while-revalidate=60
ETag: "a1c9"

API reference data

Cache-Control: public, max-age=300, s-maxage=600, stale-if-error=600
ETag: "v42"

Authenticated response

Cache-Control: private, no-store

Image with client hints

Cache-Control: public, max-age=604800
Vary: Accept, DPR, Width, Save-Data

Edge patterns that blend speed with personalization

You can keep caching even with dynamic experiences.

  • Edge logic: Simple scripts at the edge can route requests to cached or dynamic backends based on cookies that you choose to include in the cache key.
  • ESI or includes: Assemble a page from cached and private parts. For example, cache the frame and fetch the cart total separately.
  • Microfrontends: Serve a cached shell that hydrates components with fresh data.

The theme is consistent. Cache what you can, isolate the truly dynamic parts, and keep your keys clean.

Common pitfalls that slow sites down

  • Setting no-cache everywhere because of a single edge case.
  • Relying on query string cache busting for assets, then forgetting long TTLs.
  • Caching HTML for logged-in users by accident and leaking data.
  • Varying on too many headers or on raw User-Agent and blowing out the cache.
  • Forgetting to purge listing pages, sitemaps, or RSS feeds when content changes.
  • Serving private content from a shared CDN because private was missing.

Add these to your launch checklist. Small mistakes here create big performance bills later.

A simple rollout plan for teams new to caching

Week 1: Baseline and low-risk wins

  • Audit headers on your top 100 pages and assets.
  • Add hashed filenames for CSS and JS. Set long-lived immutable caching.
  • Turn on gzip and brotli. Confirm Vary: Accept-Encoding.
  • Enable a CDN in front of the site. Keep TTLs short on HTML.

Week 2: Edge revalidation and microcaching

  • Add s-maxage to anonymous HTML. Start with 60 to 120 seconds.
  • Enable stale-while-revalidate for HTML and reference APIs.
  • Microcache HTML at the reverse proxy for 1 to 5 seconds.

Week 3: Purges and tags

  • Add surrogate keys or a purge map in your CMS.
  • Automate purges on publish, update, and delete events.
  • Soft purge for routine updates, hard purge for removals.

Week 4: Object caching and measurement

  • Cache expensive fragments in Redis with explicit keys and TTLs.
  • Set up dashboards for hit ratio, origin offload, TTFB, and LCP by template.
  • Review misses and expand the TTL matrix where safe.

Small, steady changes compound into big speed gains.

Supporting sections

Caching and Core Web Vitals

Caching helps especially with LCP because it accelerates the delivery of the main image or block-level text, plus the render blocking CSS. Faster TTFB reduces the time the browser waits before it can parse HTML. Caching does not fix layout shifts outright, but it ensures your critical assets arrive on time so CLS work holds. For INP, caching trims script load and API wait times, which reduces long tasks that block input processing.

Accessibility and caching

Performance is part of accessibility. Faster pages help keyboard and screen reader users because the DOM stabilizes sooner. Caching that delivers smaller, simpler pages reduces cognitive load and energy use on low-power devices. Treat performance as a usability feature, not a vanity metric.

Security notes for cache operators

Use HTTPS end to end. Set HSTS when you are confident in your TLS setup. If you sign URLs for private media, keep keys out of edge logs and rotate them. Review your CDN’s default behavior for caching status codes and headers to avoid storing what should not be stored.

Final Takeaway

Caching is the highest leverage performance tool you can adopt because it saves time for users and work for servers at the same time. Start with long-lived immutable asset caching, add careful edge caching for HTML with revalidation, and pair it with reliable purges. Keep private data out of shared caches, measure hit ratio and user-centric metrics, and tune TTLs with a simple written matrix. When you treat caching as a product feature, speed becomes your default rather than a lucky state.

Frequently Asked Questions

Will caching hurt SEO or prevent search engines from seeing fresh content?

No. Search engines respect HTTP caching but also revalidate and recrawl important pages quickly. Use short edge TTLs on HTML with validators and purge on publish for critical pages.

Should I cache HTML at all if my site is personalized?

Yes for anonymous traffic. Cache the shell or frame and fetch personalized parts separately. Use cookies to split cache keys only for variants you truly need.

Is no-cache the same as no-store?

No. no-cache allows caches to store a response but requires revalidation before reuse. no-store forbids caches from storing the response at all. Use no-store for sensitive content.

How do I pick the right TTL without breaking freshness?

Start conservative and measure. Add stale-while-revalidate so users get fast responses while caches refresh. Automate purges for content updates so you can raise TTLs safely.

Can I rely on snapshots or server-side caching alone?

No. Pair HTTP caching with object caching and make sure you have a purge strategy. Snapshots help with rollbacks, not day to day performance.

What headers show that a response came from cache?

Look for Age with a positive number, ETag plus a 304 Not Modified on revalidation, or vendor headers like CDN-Cache-Status: HIT. Your browser’s dev tools show this on the Network tab.

References

  • IETF RFC 9111: HTTP Caching
  • MDN Web Docs: Cache-Control, ETag, Last-Modified, Vary
  • web.dev: HTTP caching best practices, Core Web Vitals overview
  • Redis documentation: Caching patterns
  • NGINX documentation: Content caching
  • Varnish documentation: Purge, ban, and surrogate keys
  • Fastly and Cloudflare docs: Cache tags and stale-while-revalidate

Links

Similar Posts