1. Measure
Turn on additional metrics for the distribution to get CacheHitRate, plus OriginLatency and error rates. The CloudFront console's popular objects and cache statistics reports show hits/misses by object type and status.
With standard logs in S3 + Athena:
SELECT x_edge_result_type, COUNT(*) AS requests
FROM cloudfront_logs
WHERE "date" >= DATE '2026-10-18'
GROUP BY x_edge_result_type ORDER BY requests DESC;
SELECT cs_uri_stem, COUNT(*) AS misses
FROM cloudfront_logs
WHERE "date" >= DATE '2026-10-18' AND x_edge_result_type = 'Miss'
GROUP BY cs_uri_stem ORDER BY misses DESC LIMIT 25;
2. Trim the cache key
Every header, cookie and query string in the cache key splits the cache. Use cache policies:
| Path | Cache policy |
|---|---|
Static assets (/static/*, *.js, *.css, images) | Managed CachingOptimized (no cookies/headers/query strings in key) |
| Pages that vary by a few params | Custom policy including only those query strings |
| APIs / personalised content | Managed CachingDisabled |
Forward what the origin needs with an origin request policy (e.g. AllViewerExceptHostHeader), separate from the cache key. Forwarding a header to the origin doesn't have to mean caching by it.
3. Cache headers from the origin
Cache-Control: public, max-age=31536000, immutable # fingerprinted assets
Cache-Control: public, max-age=300, s-maxage=600 # pages: shorter in browsers, longer at the edge
Cache-Control: private, no-store # user-specific
For S3 origins, set Cache-Control metadata at upload time (aws s3 cp --cache-control ...). Cache policies' min/default/max TTL bound what the origin says.
4. Origin Shield
An extra caching layer in one region in front of the origin. Edge locations that miss go to Origin Shield first, so the origin sees fewer requests. Useful when viewers are spread worldwide or several distributions share an origin. Pick the Origin Shield region closest to the origin. It adds a per-request charge, so measure the origin request reduction.
5. Compression
Enable "Compress objects automatically" in the cache behavior, with a cache policy that has Gzip and Brotli enabled (managed CachingOptimized does). CloudFront compresses eligible content types within its size limits when the viewer accepts it.
6. Normalise requests with CloudFront Functions
Reduce variants before they reach the cache:
function handler(event) {
var req = event.request;
// drop tracking parameters so they don't split the cache
['utm_source', 'utm_medium', 'utm_campaign', 'fbclid', 'gclid'].forEach(function (p) { delete req.querystring[p]; });
// normalise the path
req.uri = req.uri.toLowerCase();
return req;
}
Only lowercase URIs if your origin is case-insensitive; S3 keys are case-sensitive.
7. Invalidate less
Fingerprinted file names make invalidations mostly unnecessary. When you must, invalidate specific paths after deployment, not /* during peak.
8. Measure again
Targets for static-heavy sites: cache hit rate > 90% on static behaviors, origin requests down, data transfer from origin down. Then review origin capacity.
Warning
Including
Authorizationor session cookies in an origin request policy while caching responses can leak one user's content to another. Keep personalised paths onCachingDisabled, and checkCache-Control: privateon those responses.
Checklist
- Hit rate and top misses measured
- Cache policies per behavior with minimal cache keys
- Origin sends Cache-Control
- Origin Shield where viewers are global or origins shared
- Compression on
- Requests normalised; invalidations targeted