CloudFront cache TTL calculator
How long CloudFront keeps a response depends on two things that often disagree: the headers your origin sends and the TTL settings of the cache policy. Paste the headers to see which one wins, then follow a stream of requests through edge locations, regional caches and Origin Shield to see how many still reach your origin.
CloudFront caches it for 60 s.
max-age = 60 s is within the minimum (1 s) and maximum (31,536,000 s) TTL, so CloudFront uses it.
| CloudFront | 60 s |
| Browsers | 60 s (max-age) |
| Serve stale while revalidating | no |
| Serve stale if the origin fails | no |
- Requests per hour
- 360,000
- Edge hit ratio
- 99.17%
- Answered by some cache
- 99.983%
- Origin requests per hour
- 60
- Without Origin Shield
- 476
Requests are spread evenly over the edge locations and cache key variants; each layer keeps its copy for the CloudFront TTL from when it fetched it. Counts are per hour in the long run.
How to use the calculator
Paste the Cache-Control header your origin returns (with or without the header name), and an Expires time if it sends one. Choose a managed cache policy or type your own minimum, default and maximum TTL. The calculator applies the rules from the CloudFront Developer Guide and says which input decided.
The lower half follows one object through CloudFront's layers. Set how many requests a second it gets, across how many edge locations, and how many cache key variants there are: different values of headers, cookies or query strings that the cache policy includes in the key. Each variant is cached separately.
How CloudFront sets the cache time
Every CloudFront cache behaviour has three TTL settings, from the cache policy or the legacy cache settings: a minimum, a default and a maximum. CloudFront combines them with the origin's headers as follows:
- If the response has s-maxage, CloudFront uses it; otherwise max-age; otherwise the time until Expires. The value is raised to the minimum TTL if it is below it and lowered to the maximum TTL if it is above it.
- If the response has none of those, CloudFront uses the default TTL, or the minimum TTL if that is larger.
- If the response says no-cache, no-store or private, CloudFront respects it when the minimum TTL is 0 and caches for the minimum TTL otherwise.
So with the legacy defaults or CachingOptimized, a response with no caching headers is kept for 24 h, and one with max-age of two years is kept for 365 days, the maximum. With the UseOriginCacheControlHeaders policy, whose default TTL is 0, a response without caching headers is not cached at all.
The minimum TTL trap
A minimum TTL above 0 overrides the origin's request not to cache. The managed CachingOptimized policy, the usual choice for static content, has a minimum TTL of 1 second, so a response marked no-store or private is cached for 1 s and can be served to other users during that second. The CloudFront guide warns about this for the three managed policies with a minimum above 0. Personalised or sensitive responses belong behind a policy with a minimum TTL of 0, such as CachingDisabled or UseOriginCacheControlHeaders, where no-cache sends every request to the origin and no-store and private are not cached.
The guide adds a related warning: when the minimum or maximum TTL is above 0 and the origin cannot be reached, CloudFront may serve a copy it fetched earlier even if it was marked no-store. Sending stale-if-error=0 asks it to return the error instead.
CloudFront TTL and browser TTL
Unless a response headers policy changes them, CloudFront passes the origin's headers on to the browser, and browsers apply them as written: the cache policy's TTLs affect only CloudFront. HTTP caching (RFC 9111) gives shared caches their own directive for this split: s-maxage applies only to shared caches and overrides max-age there. max-age=60, s-maxage=600 lets CloudFront answer for 600 s while each browser checks again after a minute, a common setup for pages that change occasionally. An invalidation can then refresh CloudFront quickly, while no browser holds a copy for more than a minute.
Serving stale content
Two directives from RFC 5861 let a cache use an expired copy. stale-while-revalidate=N lets CloudFront answer with the expired copy for up to N seconds while it fetches a fresh one in the background, so users do not wait for the origin when the TTL runs out. stale-if-error=N lets it keep serving the expired copy for up to N seconds when the origin is unreachable or returns a 5xx error. CloudFront caps both at the maximum TTL. Together they hide both the latency of revalidation and short origin outages: max-age=600, stale-while-revalidate=60, stale-if-error=86400 keeps a page fresh for ten minutes and keeps it up for a day if the origin goes down.
Edge, regional caches and Origin Shield
A request first reaches an edge location near the user. On a miss, the edge asks a regional edge cache, a larger cache shared by the edge locations of a region, and only on a miss there does the request go further. Origin Shield, an optional extra layer, sits between all regional caches and the origin, so the origin sees at most one request per object per TTL for the whole distribution.
Each layer that keeps its own copy for the TTL sends on about one request per copy per TTL, so the origin's load depends on how many copies the top layer holds. For one object requested 100 times a second (360,000 times an hour) over 50 edge locations and 8 regional caches, the model gives:
| TTL | Edge hit ratio | Origin requests/h, no Shield | With Origin Shield |
|---|---|---|---|
| 1 s | 66.68% | 24,307 | 3,280 |
| 10 s | 95.24% | 2,763 | 348 |
| 60 s | 99.17% | 476 | 60 |
| 10 min | 99.92% | 48 | 6 |
| 60 min | 99.99% | 8 | 1 |
| 24 h | 100% | 0 | 0 |
Origin Shield cuts origin traffic by about the number of regional caches, and matters most for short TTLs and for origins that are expensive per request, such as image processing or a database-backed page. With long TTLs the origin load is already negligible.
The cache key and the hit ratio
CloudFront caches a separate copy for each distinct cache key: the URL plus whatever headers, cookies and query strings the cache policy includes. Including one with many values splits the traffic. With a 60 s TTL, adding a key component with 20 equally common values (a language header, say) lowers the edge hit ratio from 99.17% to 85.72%, and raises origin requests from 60 to 1,124 an hour with Origin Shield, or from 476 to 8,723 without it.
The cure is to include only what changes the response. The CloudFront guide separates the cache key from what is forwarded to the origin: an origin request policy can send a header to the origin without making it part of the key. Headers such as User-Agent, with thousands of values, are the classic cause of a low hit ratio; CloudFront's own device headers, such as CloudFront-Is-Mobile-Viewer, reduce them to a few values.
Invalidation and versioned file names
To replace an object before its TTL runs out, CloudFront offers invalidation: a request to remove given paths from every cache, after which the next request goes to the origin. It takes time to reach every location and does nothing for copies already in browsers. The alternative is to put a version or a content hash in the file name, such as app.3f9a2c.js, and change the reference in the HTML; the new name is a new cache key, the old copy simply expires, and both CloudFront and browsers can then cache files for the maximum TTL. The CloudFront guide recommends versioned names for files that change often, partly because an invalidation cannot reach copies already held by browsers or corporate proxies.
CloudFront caching questions and answers
How does CloudFront decide how long to cache an object?
It takes s-maxage if the origin sent one, otherwise max-age, otherwise Expires, and clamps that between the cache policy's minimum and maximum TTL. With none of the three it uses the default TTL, or the minimum if that is larger. No-cache, no-store and private are respected only when the minimum TTL is 0.
Does CloudFront cache responses marked no-store?
Yes, if the cache policy's minimum TTL is above 0. The managed CachingOptimized policy has a minimum TTL of 1 second, so a no-store response is cached for 1 s. With a minimum TTL of 0, CloudFront respects no-store, no-cache and private.
What is the difference between max-age and s-maxage?
max-age applies to every cache, including browsers; s-maxage applies only to shared caches such as CloudFront and overrides max-age there. "max-age=60, s-maxage=600" lets CloudFront keep the object for 600 s while browsers check again after 60 s.
What is the default TTL in CloudFront?
With the legacy cache settings and with the CachingOptimized policy, the default TTL is 86,400 s (24 hours) and applies when the origin sends no max-age, s-maxage or Expires. The UseOriginCacheControlHeaders policy has a default TTL of 0, so such responses are not cached. The maximum TTL in all three is 31,536,000 s (one year).
What does Origin Shield do?
It adds one more cache layer in front of the origin that all regional edge caches go through, so the origin sees one request per object per TTL instead of one per regional cache. In this page's model of 360,000 requests an hour with a 60 s TTL, the origin gets 476 requests an hour without Origin Shield and 60 with it.
Why is my CloudFront cache hit ratio low?
Usually because the TTL is short, or the cache key includes headers, cookies or query strings that take many values, which splits traffic into many separately cached copies. Adding a key component with 20 values to the example drops the edge hit ratio from 99.17% to 85.72%.
Further reading
- CloudFront Developer GuideManage how long content stays in the cacheThe full table of origin headers against minimum TTL, and the stale directives.
- CloudFront Developer GuideUse managed cache policiesThe TTLs and cache keys of CachingOptimized, CachingDisabled and the others.
- CloudFront Developer GuideUse Amazon CloudFront Origin ShieldWhen the extra layer helps and how to choose its Region.
- RFC 9111HTTP Cachingmax-age, s-maxage, Expires and the meaning of no-cache and no-store.
- RFC 5861HTTP Cache-Control Extensions for Stale Contentstale-while-revalidate and stale-if-error.