What are the practical differences between when CloudFront expires objects at an origin via the CloudFront TTL setting versus when one calls invalidate?
-
Can you expand on your question, specifically what you mean by "practical differences?" For example, there are potential behavioral differences on how CloudFront interacts with the origin when a request arrives for an object that is cached but expired vs an object that has been invalidated. What prompted the question? – Michael - sqlbot May 25 '18 at 13:38
-
Reason for the question -- I'm trying to choose whether to use TTL or Invalidation. Looking for more information on their differences. – BestPractices May 28 '18 at 23:56
2 Answers
The general idea is that you use TTLs to set the policy that CloudFront uses to determine the maximum amount of time each individual object can potentially be served from the CloudFront cache with no further interaction with the origin.
Default TTL: the maximum time an object can persist in a CloudFront cache without being considered stale, when no relevant Cache-Control
directive is supplied by the origin. No Cache-Control
header is added to the response by CloudFront.
Minimum TTL: If the origin supplies a Cache-Control: s-maxage value (or, if not present, then a Cache-Control: max-age value) smaller than this, CloudFront ignores it and assumes it can retain the object in the cache for not longer than this. For example, if Minimum TTL is set to 900, but the response contains Cache-Control: max-age=300
, CloudFront ignores the 300 and may cache the object for up to 900 seconds. The Cache-Control
header is not modified, and is returned to the viewer as received.
Maximum TTL: If the origin supplies a Cache-Control
directive indicating that the object can be cached longer than this, CloudFront ignores the directive and assumes that the object must not continue to be served from cache for longer than Maximum TTL.
See Specifying How Long Objects Stay in a CloudFront Edge Cache (Expiration) in the Amazon CloudFront Developer Guide.
So, these three values control what CloudFront uses to determine whether a cached response is still "fresh enough" to be returned to subsequent viewers. It does not mean CloudFront purges the cached object after the TTL expires. Instead, CloudFront may retain the object, but will not serve it beyond the expiration without first sending request to the origin to see if the object has changed.
CloudFront does not proactively check the origin for new versions of objects that have expired -- it only checks if they are requested again, while still in the cache, and then determined to have been expired. When it does this, it usually sends a conditional request, using directives like If-Modfied-Since
. This gives the origin the option of responding 304 Not Modified
, which tells CloudFront that the cached object is still usable.
A misunderstanding that sometimes surfaces is that the TTL directs CloudFront how long to cache the objects. That is not what it does. It tells CloudFront how long it is allowed to cache the response with no revalidation against the origin. Cache storage inside CloudFront has no associated charge, and caches by definition are ephemeral, so, objects that are rarely requested may be purged from the cache before their TTL expires.
If an object in an edge location isn't frequently requested, CloudFront might evict the object—remove the object before its expiration date—to make room for objects that have been requested more recently.
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
On the next request, CloudFront will request the object from the origin again.
Another misunderstanding is that CloudFront's cache is monolithic. It isn't. Each of the global edges has its own independent cache, caching objects in edges through which they are being requested. Each global edge also has an upstream regional cache (in the nearest EC2 region; there may be more than one per region, but this isn't documented) where the object will also be stored, allowing other nearby global edges to find the object in the nearest regional cache, but CloudFront does not search any further, internally, for cached objects. For performance, it just goes to the origin on a cache miss.
See How CloudFront Works with Regional Edge Caches.
Invalidation is entirely different, and is intended to be used sparingly -- only the first 1000 invalidation paths submitted each month by an AWS account are free. (A path can match many files, and the path /*
matches all files in the distribution).
An invalidation request has a timestamp of when the invalidation was created, and sends a message to all regions, directing them to do something along these lines (the exact algorithm isn't documented, but this accurately descibes the net effect):
- Delete any files matching
${path}
from your cache, if they were cached prior to${timestamp}
and - Meanwhile, since that could take some time, if you get any requests for files matching
${path}
that were cached prior to${timestamp}
, don't use the cached files because they are no longer usable.
The invalidation request is considered complete as soon as the entire network has received the message. Invalidations are essentially an idempotent action, in the sense that it is not an error to invalidate files that don't actually exist, because an invalidation is telling the edges to invalidate such files if they exist.
From this, it should be apparent that the correct course of action is not to choose one or the other, but to use both as appropriate. Set your TTLs (or select "use origin cache headers" and configure your origin server always to return them with appropriate values) and then use invalidations only as necessary to purge your cache of selected or all content, as might be necessary if you've made an error, or made significant changes to the site.
The best practice, however, is not to count on invalidations but instead to use cache-busting techniques when an object changes. Cache busting means changing the actual object being requested. In the simplest implementstion, for example, this might mean you change /pics/cat1.png to /pics/cat2.png in your HTML rather than saving a new image as /pics/cat1.png when you want a new image. The problem with replacing one file with another at the same URL is that the browser also has a cache, and may continue displaying the old image.
See also Invalidating Objects.
Note also that the main TTLs are not used for error responses. By default, responses like 404 Not Found
are cached for 5 minutes. This is the Error Caching Minimum TTL, designed to relieve your origin server from receiving requests that are likely to continue to fail, but only for a few minutes.

- 169,571
- 25
- 353
- 427
-
thanks for your reply. can you edit/clean it up a bit -- you state in the first sentence that TTL is used for no longer than, but then alter you also say it is used for at least then. can you clarify this sentence? also, can you cite sources for your statements. – BestPractices May 29 '18 at 14:05
-
@BestPractices I'm not finding where I used the phrase "at least" or something similar. I've reworded and added citations. Please advise if there is any remaining ambiguity. – Michael - sqlbot May 29 '18 at 18:17
-
it used to be in your first sentence. In place of "at least" it now says "uses to determine the maximum amount of time each individual". That's still not quite accurate since there are a min, max, and default setting for TTL (it's not just "maximum"). perhaps a SO editor edited your post. – BestPractices May 29 '18 at 21:16
-
The only edit to the post was the one I made. What you are not seeing is there is indeed just one derived value per object, which is the **maximum** time CloudFront will consider the object fresh. The maximum lifetime for each object is set to... (1) the Maximum TTL when Cache-Control specifies a longer life than that value, or (2) the Minimum TTL when Cache-Control specifies a shorter life than that value, or (3) the Default TTL when Cache-Contol does not specify a lifetime, otherwise (4) the value specified by Cache-Control. Whatever the result, that's the maximum lifetime of the object. – Michael - sqlbot May 29 '18 at 23:05
-
I'm confused, you wrote this -- seems like it also can set a *minimum* time: "Minimum TTL: If the origin supplies a Cache-Control: s-maxage value (or, if not present, then a Cache-Control: max-age value) smaller than this, CloudFront ignores it and assumes it can retain the object in the cache for not longer than this." – BestPractices May 30 '18 at 13:36
-
@BestPractices Cache-Control establishes the maximum. Minimum TTL constrains the lower bound of that maximum. `Cache-Control: s-maxage=30` means a *maximum* lifetime ("max age") of 30 seconds. If Minimum TTL is set to 60, CloudFront ignores the 30 and assumes a maximum lifetime of 60. To state it another way, the three TTL parameters could be described as Minimum Maximum TTL, Maximum Maximum TTL, and Default Maximum TTL, but TTL here implies "maximum," since the TTL is the maximum amount of time CloudFront can assume the object is fresh. – Michael - sqlbot May 30 '18 at 13:45
-
I wouldnt state it that way -- CloudFront is changing the *minimum* lifetime to 60. It is not setting the maximum to 60. If you feel it is, please point to where it says that in the docs. – BestPractices May 30 '18 at 20:41
-
1No, it is not changing the minimum lifetime. It is imposing a minimum value on the maximum lifetime of the object in the cache. *["`max-age < minimum TTL`: CloudFront caches objects for the value of the CloudFront minimum TTL."](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html?shortFooter=true#ExpirationDownloadDist)* thereby setting the maximum possible lifetime in the cache to the value of Minimum TTL. You cannot dictate how long CloudFront **must** cache an object (a minimum), you can only dictate how long it is allowed to cache the object (maximum). – Michael - sqlbot May 30 '18 at 21:48
-
See here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesMinTTL "Minimum TTL - Specify the **minimum amount of time, in seconds, that you want objects to stay in CloudFront caches** before CloudFront forwards another request to your origin to determine whether the object has been updated. The default value for Minimum TTL is 0 seconds" – BestPractices Jun 03 '18 at 22:57
-
The most important part is **before CloudFront forwards another request to the origin**. The *maximum* amount of time CloudFront will cache the object without revalidating it with the origin will not be set smaller than this minimum value, even if Cache-Control sets a smaller value. This is not the minimum amount of time the object stays in the cache. This is the minimum amount of time **you want** the object to be considered fresh, even if Cache-Control specifies otherwise. That is *all* this setting does. – Michael - sqlbot Jun 04 '18 at 01:14
-
Awesome answer. Thanks @Michael-sqlbot. Helpful as usual. I wonder why it is not marked as a correct answer. – yuranos Apr 07 '19 at 17:28
If we are looking at practical differences:
- CloudFront TTL: You can control how long your objects stay in a CloudFront cache before CloudFront forwards another request to your origin.
- Invalidate: Invalidate the object from edge caches. The next time a viewer requests the object, CloudFront returns to the origin to fetch the latest version of the object.
So the main difference is speed. If you deploy a new version of your application you might want to invalidate immediately.

- 7,483
- 4
- 44
- 62