The Contrarian Claim: Your CDN Isn't the Problem, Your Headers Are
Every week, some engineer tells me their CDN is underperforming. They tweak eviction policies, fiddle with Redis, even switch load balancers. But nine times out of ten, the real villain is the Cache-Control header—or the lack of one. I'm not exaggerating: I've watched a "CDN issue" vanish in minutes once someone set Cache-Control: max-age=604800 on a static asset. So before you blame the network, look in the mirror.
Imagine You're Running a Product Page
Picture this: you're the lead engineer for a mid-sized e-commerce site. Your product pages are dynamic—prices change, stock fluctuates—so you've never cached them. Your CDN is serving your static JS and images, but your hit ratio hovers around 50%. Users complain about slow loads. Your origin server is sweating. You've tried everything: purging, tweaking Redis, even switching from round-robin to least-connections (HAProxy). But the real fix is in your HTTP headers.
Step 1: Set Explicit Freshness, Not Hope
First, understand what your CDN does by default. Cloudflare, for instance, will cache certain status codes if you don't send any cache-control headers—200s for 120 minutes, 302s for 20, 404s for 3 (Cloudflare). That's a recipe for stale content and low hit ratios. Instead, you need to be explicit. The Cache-Control header is your primary tool. It can carry directives like max-age, s-maxage, and public. For your product images, you might set Cache-Control: max-age=604800, public—that keeps them fresh for 7 days (MDN). But product pages need a shorter TTL, say max-age=60.
Step 2: Use Validators to Avoid Full Re-Fetches
Even with a short TTL, you can avoid downloading the whole page on every change. That's where validators come in. An ETag is a version identifier for a resource; when the content hasn't changed, the server doesn't need to resend the full response (MDN). Similarly, Last-Modified provides a fallback date (MDN). Configure your origin to send these, and your CDN can do conditional requests, saving bandwidth and time.
Step 3: Don't Forget Vary for Content Negotiation
If you're serving different content based on request headers—like Accept-Encoding for gzip or Accept-Language for translations—you must use the Vary header. It tells caches to store separate versions per header value, so you don't serve a compressed file to a client that can't handle it (MDN). Without it, you'll get cache poisoning and confused users.
Step 4: Adopt Stale-While-Revalidate for Graceful Aging
Now, what about those moments when a cached response is stale but the origin is slow? RFC 5861 introduced stale-while-revalidate, which lets a cache serve a stale response for up to a specified number of seconds while revalidating in the background (RFC 5861). This is a game-changer for dynamic pages: set Cache-Control: max-age=60, stale-while-revalidate=30. Your CDN can instantly serve the stale copy while fetching a fresh one, hiding latency. I recommend this for any page that can tolerate a 30-second lag.
Step 5: Purge Strategically, Not Desperately
When you do need to invalidate, don't purge everything. Cloudflare's purge by single-file removes a specific URL from all edge caches instantly (Cloudflare). Use that for targeted updates, like when a product price changes. You can also rely on HTTP semantics: per RFC 9111, unsafe methods like POST or DELETE must invalidate the cached URI when they succeed (RFC 9111). So your origin should be sending the right status codes, and your CDN will handle the rest.
The Takeaway
Stop blaming your CDN. Start with your Cache-Control headers. Set explicit max-age or s-maxage, use ETags and Last-Modified, respect Vary, and adopt stale-while-revalidate. Your hit ratio will climb, your origin will breathe, and your users will thank you. Trust me—I've seen it happen.
Sources
- MDN (Cache-Control) - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- RFC 5861 (stale-while-revalidate) - https://www.rfc-editor.org/rfc/rfc5861.txt
- Cloudflare (purge by single-file) - https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-single-file/
- RFC 9111 (HTTP Caching) - https://httpwg.org/specs/rfc9111.html
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!