HTTP Caching Explained: ETag, Cache-Control and CDNs

Web2026-09-28TryQuickToolBox

Why Your Website Feels Slow (And How Caching Fixes It)

You've optimized your images, minified your CSS, and even upgraded your server. Yet repeat visitors still experience slow load times, and your origin server is burning bandwidth. The culprit? Inefficient HTTP caching. Without proper caching headers, browsers re-download the same assets on every visit, and CDNs can't do their job effectively.

HTTP caching is one of the highest-leverage performance optimizations available. It reduces latency, cuts bandwidth costs, and lightens the load on your origin servers. In this guide, we'll break down the key mechanisms: ETag, Cache-Control, and how CDNs fit into the picture. You'll learn practical strategies to implement them correctly.

How HTTP Caching Works: The Big Picture

When a browser requests a resource, it can either fetch it from the origin server or serve a locally stored copy. HTTP caching defines the rules for when a stored copy is considered fresh and when it must be revalidated.

Two main types of caching exist:

Both rely on HTTP headers to decide freshness and revalidation. The two most important headers are Cache-Control and ETag.

Cache-Control: The Freshness Rules

Cache-Control is the primary header for defining caching policies. It's a directive-based header that tells caches how to treat a response.

Key Directives

Example: Cache-Control: public, max-age=31536000, immutable is ideal for static assets with hashed filenames.

ETag and Conditional Requests

An ETag (Entity Tag) is an identifier for a specific version of a resource. When a resource changes, the ETag changes. Browsers use ETags to make conditional requests: they send the stored ETag in an If-None-Match header. If the resource hasn't changed, the server responds with 304 Not Modified and no body, saving bandwidth.

Similarly, Last-Modified works with If-Modified-Since, but ETags are more precise (they can detect changes within the same second).

How to Generate ETags

Most web servers and frameworks generate ETags automatically. For example, in Express.js you can enable it with app.set('etag', 'strong'). In Nginx, ETags are on by default for static files.

Strong ETags (e.g., "abc123") guarantee byte-for-byte identity. Weak ETags (e.g., W/"abc123") indicate semantic equivalence, not exact bytes.

CDN Caching: Shared Cache at Scale

CDNs (Content Delivery Networks) act as shared caches distributed globally. They cache your content at edge locations, serving it to users from a nearby point of presence. This reduces latency and offloads your origin.

CDNs respect Cache-Control headers but often have their own configuration. Key concepts:

When using a CDN, set Cache-Control with s-maxage to control shared cache freshness separately from browser cache. For example: Cache-Control: public, max-age=600, s-maxage=3600 means browsers cache for 10 minutes, but the CDN caches for 1 hour.

Comparison of Caching Headers

Header Purpose Example
Cache-Control Defines freshness and caching rules public, max-age=3600
ETag Unique identifier for a resource version "abc123"
Last-Modified Timestamp of last modification Wed, 21 Oct 2025 07:28:00 GMT
Expires Legacy absolute expiration date Wed, 21 Oct 2025 07:28:00 GMT
Vary Specifies headers that affect caching Accept-Encoding

Note: Expires is superseded by Cache-Control but still used by older clients.

Practical Caching Strategy for Web Apps

Follow these steps to implement effective caching:

  1. Fingerprint static assets: Use hashed filenames (e.g., app.a1b2c3.js) and set long max-age with immutable. When the file changes, the hash changes, busting the cache.
  2. Set appropriate Cache-Control for HTML: HTML should usually be no-cache or a short max-age so users get updates quickly. Use ETag for revalidation.
  3. Use Vary: Accept-Encoding: If you serve compressed and uncompressed versions, this ensures caches store them separately.
  4. Leverage CDN with s-maxage: Set longer s-maxage for shared caches to reduce origin load, while keeping browser cache shorter if needed.
  5. Invalidate wisely: Use CDN purge APIs when deploying critical updates. For static assets, fingerprinting avoids the need for purging.
  6. Monitor cache hit ratio: Use CDN analytics to ensure your cache is effective. Low hit ratio means misconfigured headers.

Common Pitfalls and How to Avoid Them

Testing Your Caching Setup

Use browser DevTools (Network tab) to inspect response headers and see if resources are served from cache (look for "(from disk cache)" or "(from memory cache)"). For CDN behavior, use curl -I to check headers like X-Cache or CF-Cache-Status. Tools like WebPageTest can visualize caching across visits.

FAQ

What is the difference between ETag and Last-Modified?

ETag is an opaque identifier that changes when the resource changes, while Last-Modified is a timestamp. ETags are more precise because they can detect changes within the same second and don't rely on clock synchronization.

When should I use no-cache vs no-store?

Use no-cache when you want the cache to store the response but revalidate it with the origin before each use. Use no-store for sensitive data that must never be written to disk or memory by any cache.

How do CDNs handle cache invalidation?

CDNs provide purge APIs that let you remove specific URLs or entire directories from their edge caches. Some also support soft purges that mark content as stale and revalidate on next request. Fingerprinting assets is often more efficient than purging.

Conclusion

Mastering HTTP caching with ETag, Cache-Control, and CDNs is essential for building fast, scalable web applications. Start by setting proper headers for your static assets and HTML, leverage CDN shared caches with s-maxage, and always test your configuration. Small changes in caching headers can lead to significant performance gains.

Need to quickly analyze your server logs to see cache hit ratios? Try our Nginx Log Analyzer to parse and visualize your access logs.