By Harry Roberts
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Written by Harry Roberts on CSS Wizardry.
N.B. All code can now be licensed under the permissive MIT license. Read more about licensing CSS Wizardry code samples…
Try out the max-age
calculator.
If you wanted to cache a file ‘forever’, you’d probably use a Cache-Control
header like this:
Cache-Control: max-age=31536000
This instructs any cache that it may store and reuse a response for one year (60
seconds × 60 minutes × 24 hours × 365 days = 31,536,000 seconds). But why
one year? Why not 10 years? Why not max-age=forever
? Why not max-age=∞
?!
I wondered the same. Let’s find out together.
It’s 2147483648
seconds, or 68 years. To find out why, read on!
max-age
max-age
is a Cache-Control
directive that instructs a cache that it may
store and reuse a response for n seconds from the point at which it
entered the cache in question. Once that time has elapsed, the cache should
either revalidate the file with the origin server, or do whatever any
additional directives may have instructed it to
do. But why might we want to have
a max-age
that equates to forever?
immutable
If we’re confident that we can cache a file for a year, we must be also quite confident that it never really changes. After all, a year is a very long time in internet timescales. If we have this degree of confidence that a file won’t change, we can cache the file immutably.
immutable
is a relatively
new
directive that effectively makes a contract with the
browser in which we as
developers tell the browser: this file will never, ever change, ever;
please don’t bother coming back to the server to check for updates
.
Let’s say we have a simple source CSS file called button.css
. Its content is
as follows:
.c-btn {
background-color: #C0FFEE;
}
Once our build system has completed, it will fingerprint the file and export it
with a unique hash, or fingerprint, in its filename. The MD5 checksum for this
file is 7fda1016c4f1eaafc5a4e50a58308b79
, so we’d probably end up with a file
named button.7fda1016.css
.
If we change the colour of the button, the next time we roll a release, the build step will do its thing and now, the following content:
.c-btn {
background-color: #BADA55;
}
…would have a checksum of 6bb70b2a68a0e28913a05fb3656639b6
. In that case, we’d
call the new file button.6bb70b2a.css
.
Notice how the content of the original file button.7fda1016.css
hasn’t
changed; button.7fda1016.css
has ceased to exist entirely, and is replaced by
a whole new file called button.6bb70b2a.css
.
Fingerprinted files never change—they get replaced. This means we can safely cache any fingerprinted file for, well, forever.
But how long is forever?!
31536000
SecondsTraditionally, developers have set ‘forever’ max-age
values at 31536000
seconds, which is a year. Why a year, though? A year isn’t forever. Was
31536000
arrived at by agreement? Or is it specified somewhere? RFC
2616 says of the
Expires
header:
To mark a response as “never expires,” an origin server sends an
Expires
date approximately one year from the time the response is sent. HTTP/1.1 servers SHOULD NOT sendExpires
dates more than one year in the future.
Historically—very historically—caching was bound to approximately one year
from the time the response is sent
. This restriction was introduced by the
long defunct Expires
header, and we’re talking about max-age
, which is
a Cache-Control
directive. Does Cache-Control
say anything different?
2147483648
SecondsIt turns out there is a maximum value for max-age
, and it’s defined in RFC
9111’s
delta-seconds
:
A recipient parsing a delta-seconds value and converting it to binary form ought to use an arithmetic type of at least 31 bits of non-negative integer range. If a cache receives a delta-seconds value greater than the greatest integer it can represent, or if any of its subsequent calculations overflows, the cache MUST consider the value to be 2147483648 (231) or the greatest positive integer it can conveniently represent.
The spec says caches should accept a maximum max-age
value of
whatever-it’s-been-told, falling back to 2,147,483,648 seconds (which is 68
years), or failing that, falling back to as-long-as-it-possibly-can. This
wording means that, technically, there isn’t a maximum as long as the cache
understands the value you passed it. Theoretically, you could set
a max-age=9999999999
(that’s 317 years!) or higher. If the cache can work with
it, that’s how long it will store it. If it can’t handle 317 years, it should
fall back to 2,147,483,648 seconds, and if it can’t handle that, whatever the
biggest value it can handle.
And why 2,147,483,648 seconds?
In a 32-bit system, the largest possible integer that can be represented in
binary form is 01111111111111111111111111111111
: a zero followed by 31 ones
(the first zero is reserved for switching between positive and negative values,
so 11111111111111111111111111111111
would be equal to -2,147,483,648).
Honestly, no.
It’s unlikely that a year would ever be insufficient, and it’s also unlikely that any cache would store a file for that long anyway: browsers periodically empty their cache as part of their general housekeeping, so even files that have been stored for a year might not actually make it that long.
This post was mostly an exercise in curiosity. But, if you wanted to, you could
go ahead and swap all of your 31536000
s for 2147483648
s. It works in all
major browsers.
N.B. All code can now be licensed under the permissive MIT license. Read more about licensing CSS Wizardry code samples…
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Hi there, I’m Harry Roberts. I am an award-winning Consultant Web Performance Engineer, designer, developer, writer, and speaker from the UK. I write, Tweet, speak, and share code about measuring and improving site-speed. You should hire me.
You can now find me on Mastodon.
I help teams achieve class-leading web performance, providing consultancy, guidance, and hands-on expertise.
I specialise in tackling complex, large-scale projects where speed, scalability, and reliability are critical to success.