A CloudFront cache policy sets Minimum TTL to 3600, Default TTL to 86400 and Maximum TTL to 31536000. The origin returns Cache-Control: no-cache on an HTML page, yet viewers keep getting an hour-old copy. Explain how CloudFront combines its own TTL settings with the origin's caching headers.
answer
- floor, ceiling, and a fallback
- origin proposes, policy disposes
- default only when origin says nothing
- a non-zero floor beats no-cache
- Age header betrays the pinning
basics
~20 sCloudFront clamps the origin's declared lifetime between the cache policy's Minimum and Maximum TTL, and uses Default TTL only when the origin declares nothing. A Minimum TTL above zero therefore overrides the origin's no-cache and pins the object for at least that long.
solid answer
~50 sA cache policy's three TTLs are not alternatives; they compose with what the origin sends. If the origin declares a lifetime — `Cache-Control: max-age` or `Expires` — CloudFront caches for that value, raised to **Minimum TTL** if it is lower and lowered to **Maximum TTL** if it is higher. If the origin declares nothing at all, CloudFront uses **Default TTL**, still clamped by the minimum. The trap in this scenario is the interaction with `no-cache`: with Minimum TTL at 0, CloudFront honours `no-cache`, `no-store` and `private` and does not serve a stored copy without going back to the origin. With Minimum TTL at 3600, the floor wins and CloudFront serves the object for an hour regardless. The fix is a separate cache behavior for HTML whose policy has Minimum TTL 0, leaving the origin in charge; keep the long-TTL policy for hashed static assets where the floor is harmless.
go deeper
Recall that CloudFront has its own TTL settings that sit on top of whatever the origin sends, so a page can stay cached even when the origin asked for no caching.
Be ready to work the arithmetic out loud: minimum is a floor, maximum a ceiling, default a fallback used only for silent origins — and apply it to a given max-age value.
Demonstrate diagnosis and remedy: read Age and X-Cache, identify a floor overriding the origin, and split the distribution into behaviors so documents stay origin-governed while hashed assets stay long-lived.
Own the policy: who is allowed to raise a floor and under what review, since a non-zero minimum silently strips applications of control over their own freshness and shows up months later as unexplained staleness.
## The three knobs A CloudFront cache policy carries `MinTTL`, `DefaultTTL` and `MaxTTL` (seconds). They are frequently misread as "pick one". They are a clamp plus a fallback. - **Minimum TTL** — a **floor**. CloudFront will not go back to the origin sooner than this, no matter what the origin said. - **Maximum TTL** — a **ceiling**. However long the origin asked for, CloudFront will not exceed this. - **Default TTL** — a **fallback**, used only when the origin's response carries no cache-lifetime header of its own. ## The resolution rules **Case 1 — the origin declares a lifetime.** For a response with `Cache-Control: max-age=N` (or an `Expires` date), the effective CloudFront TTL is `N` clamped into `[MinTTL, MaxTTL]`. Default TTL plays no part. So `max-age=60` under a Minimum TTL of 300 is cached for 300 seconds, and `max-age=604800` under a Maximum TTL of 86400 is cached for a day. **Case 2 — the origin declares nothing.** No `Cache-Control` lifetime, no `Expires`: CloudFront uses **Default TTL**, still respecting the floor. This is the case that surprises people the first time they front an app that simply never set caching headers — the CDN starts caching pages it was never told it could cache, for a full day under the common defaults. **Case 3 — the origin declares it must not be reused.** `Cache-Control: no-cache`, `no-store` or `private`. With **Minimum TTL 0**, CloudFront respects the instruction and will not serve a stored copy without revalidating with the origin. With **Minimum TTL greater than 0**, the floor wins: CloudFront serves the object for at least that long, and the origin's instruction is effectively ignored for that window. That is exactly the scenario in the question. The mental one-liner: *the origin proposes, the cache policy disposes — within a floor and a ceiling.* ## Why the scenario produces exactly this symptom Minimum TTL 3600 with a `no-cache` origin means each edge stores the HTML on the first miss and keeps answering from it for an hour. The page changes at the origin, nobody sees it, and the caching headers look correct to whoever wrote them — because they are correct, and are being overridden a layer up. Hence the classic diagnosis: read the **cache policy** before you read the origin headers. The response tells you what happened, too. CloudFront returns `X-Cache: Hit from cloudfront` and an `Age` header counting the seconds since the object was fetched. An `Age` climbing toward 3600 on a document that declares `no-cache` is the signature of a Minimum TTL floor. ## The right shape for a site One policy rarely fits a whole distribution, which is why cache behaviors exist per path pattern: - **Hashed static assets** (`/assets/*` with content hashes in the filename): a long-lived policy is ideal. Minimum TTL can be non-zero because the URL changes whenever the bytes change, so pinning is harmless. AWS's managed `CachingOptimized` policy is built for exactly this. - **HTML documents and API responses**: Minimum TTL 0, so the origin's own directives govern. If the origin says `no-cache`, CloudFront revalidates; if it says `max-age=60`, you get a minute of edge caching that absorbs bursts. The managed `CachingDisabled` policy is the zero-caching extreme of this. ```text /assets/* -> long-TTL cache policy (MinTTL 1, DefaultTTL 86400, MaxTTL 31536000) /* -> origin-governed policy (MinTTL 0, DefaultTTL 0, MaxTTL 31536000) ``` ## Practical cautions - **Raising Minimum TTL is a blunt instrument.** It is tempting when an origin is overloaded and sends poor headers, but it takes control away from the application permanently and silently. Fixing the origin's headers is the durable answer; a floor is a stopgap that someone will debug for an afternoon a year from now. - **Changing a TTL is not retroactive.** Objects already cached keep the lifetime computed when they were stored. Lowering Minimum TTL does not free the copies already pinned — for those you need an invalidation. - **Default TTL 0 is not "no caching".** It only means "cache nothing extra when the origin says nothing"; an origin that sends a long `max-age` is still honoured up to Maximum TTL. - **Set the values deliberately per behavior.** Copying one policy across every path pattern is how an HTML document ends up with a one-hour floor.
- An origin sends Cache-Control: max-age=60 and the cache policy has Minimum TTL 300 and Maximum TTL 86400. How long does CloudFront serve without returning to the origin?300 seconds. The origin's 60 seconds is below the floor, so the floor wins; Maximum TTL is irrelevant here because it only caps values that exceed it, and Default TTL is unused because the origin declared a lifetime.
- You lower Minimum TTL from 3600 to 0. Do already-cached objects start revalidating immediately?No. Objects cached under the old policy keep the lifetime computed when they were stored, so a pinned copy stays pinned for the remainder of its hour. To clear them now, submit an invalidation for the affected paths; the policy change only governs objects fetched afterwards.
- Your origin sends no caching headers at all. What does CloudFront do?It falls back to the cache policy's Default TTL, clamped by Minimum TTL. With the common one-day default that means dynamic pages get cached for 24 hours by accident — which is why an origin that fronts a CDN should always declare its intent explicitly rather than relying on CDN defaults.
saying these in an interview costs you the question
- Thinks Default TTL always applies regardless of origin headers
- Believes CloudFront always honours no-cache from the origin
- Treats the three TTLs as mutually exclusive alternatives
- Expects a lowered TTL to release already-cached objects
- Applies one long-TTL policy to HTML and hashed assets alike