CDN Cache Hit Ratio Optimization: Practical Strategies to Improve CDN Performance

Cache hit ratio is a dual gauge for both cost and experience: the higher it is, the fewer origin requests, the lighter the origin load, the lower the latency users see, and the smaller your origin bandwidth bill. Plenty of site owners flip the "CDN on" switch and never look at the hit ratio again — mediocre CDN acceleration and unimpressive savings. This article walks through immediately actionable techniques, roughly in order of impact.

1. Understand the Two Hit Ratios First

  • Byte Hit Ratio: percentage of traffic served directly by the CDN, typically should be > 85%
  • Request Hit Ratio: percentage of requests handled directly by the CDN, typically should be > 90%

They differ: HTML pages generate few requests but small bytes; images generate many requests and large bytes. If byte hit ratio is low, dynamic content or uncached endpoints are usually the culprit. So read both together: a low request hit ratio usually points at dynamic endpoints, a low byte hit ratio at uncached images or video.

Ideal Hit Ratios by Content Type

Content Type Ideal Hit Ratio Notes
Images > 95% Rarely changes
CSS/JS > 95% Changes with version updates
Font files > 99% Almost never changes
HTML pages 50-80% Depends on update frequency
API responses 0-50% Depends on cacheability

2. Eight Techniques You Can Ship Today

Tip 1: Set TTL by Resource Type

Don't use one TTL for everything. Images get 30 days + immutable, versioned CSS/JS get a year, HTML gets just 1 hour:

# Images - long cache
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

# CSS/JS - with versioning
location ~* \.(css|js)$ {
    expires 365d;
    add_header Cache-Control "public, immutable";
}

# HTML - short cache
location ~* \.html$ {
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
}

Beyond TTL, combine directives like s-maxage (shared-cache duration) and stale-if-error (keep serving stale content when the origin is down) for better fault tolerance.

Tip 2: Version Files, Don't Use Query Params

style.css?v=1 looks like a different URL to most CDNs, so every release triggers an origin fetch. Hashing the filename is the standard approach and pairs with immutable for a year-long cache:

# ❌ Not recommended
style.css?v=1

# ✅ Recommended
style.a1b2c3d4.css
main.55e8c9f1.js

Modern build tools (Vite, Webpack, Next.js) emit hashed filenames by default — just enable it in the build config. Pair them with a service worker or preload of build artifacts for further skeleton caching — nice to have, but get the hashed filenames right first.

Tip 3: Remove Dynamic Parameters from URLs

URLs carrying session IDs or random tokens create a flood of "fake unique" cache entries that drag the hit ratio down. If your CDN supports ignoring the query string, turn it on — the hit ratio often improves immediately. But if the parameter genuinely changes the response (like pagination), don't ignore it blindly — move to a canonical path-based scheme first.

Tip 4: Strip Cookies from Responses

A Set-Cookie header blocks CDN caching outright. Clear cookies on static assets and leave dynamic pages to a dedicated policy:

# Clear cookies for static resources
location ~* \.(jpg|css|js)$ {
    add_header Cache-Control "public";
    add_header Set-Cookie "";
}

Tip 5: Prefetch Popular Content

Pre-fetch pulls popular MISS content to edge nodes during idle time, so the next user request hits:

CDN Pre-fetch Strategy:
1. Analyze cache MISS requests
2. Identify popular MISS content
3. Proactively pull to edge nodes
4. Reduce future MISS occurrences

Tip 6: Tiered Caching

Edge nodes have short TTLs and refresh fast; middle-tier nodes have long TTLs and large capacity. Origin fetches happen only at the middle tier, cutting origin load by an order of magnitude:

User → Edge Node (100ms TTL) → Tiered Node (1h TTL) → Origin Server

Tip 7: Cache POST Responses

For query-like POSTs where the same body yields the same result, some CDNs can cache by request body (check support) — a meaningful reduction in origin traffic:

Cache-Control: public, max-age=3600
CDN-Cache: POST requests with same body

Tip 8: Find Problem Resources in Logs

Pull the HIT/MISS distribution regularly, sort the most-missed resources by bytes, and attack the "big AND missing" images and JS first.

Two advanced tricks deserve their own mention. First, stale-while-revalidate: the CDN serves the old copy while refreshing in the background, so users never wait on an origin fetch — great for news and leaderboard-style content. Second, Vary headers: when the same URL serves different versions by device, Vary: User-Agent splits the cache and can hurt the hit ratio; prefer URL-based differentiation (an m. domain or path prefix) instead.

Reference: Cloudflare cache docs https://developers.cloudflare.com/cache/; HTTP Cache-Control on MDN https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

3. A Real Tuning Case

An image site was stuck at a 68% hit ratio after enabling its CDN. Logs showed two culprits: half the traffic came from a carousel endpoint carrying a random timestamp parameter, and the rest from sprite images without immutable. The fix: an ignore-query-string rule for the carousel endpoint, plus hashed filenames with immutable in the build script. A week later byte hit ratio reached 94% and origin bandwidth costs dropped 40%.

16IDC Tips

Run a one-week baseline and record hit ratio and origin traffic first. Then optimize in this order — TTL → versioning → drop dynamic params → cookies — and wait two or three days after each change before judging, so you know what actually moved the needle. For latency-sensitive workloads, the jump from 70% to 95% hit ratio is something users can feel. And put hit ratio and origin bytes into your monitoring dashboard, watched together with origin CPU/bandwidth — a sudden origin surge is usually the first sign of a hit-ratio dip.