Default Browser Cache TTL Gotcha with Cloudflare
Asset Loading
In my last article I shared how I upgraded a Rails app from Sprockets to Propshaft. This was a great simplification and improvement overall. But something wasn’t quite right. I kept noticing that there was a latency on the home page as some JavaScript was being loaded.
Locally things were lightning fast, and it was starting to bug me what the
issue could be. Opening up the web inspector I noticed that locally the
cache-control
header was being set with max-age=31536000
which is the
Rails default and described in the Rails Guides here and equates to 1 year in seconds.
But in production max-age
was being set to 14400
which is 4 hours! Here’s
what it looked like comparing the responses in the Web Inspector:
Cloudflare
What I didn’t mention in the last article, is that I use Cloudflare for DNS and managing SSL certificates and it works great out of the box. They also provide a global cache built in which is great! Or is it…
Cloudflare puts it’s cache in front of the webserver which is what we want, but I hadn’t realized that the default cache time is 4 hours! That rings a bell?!
Cache Rules
Since our lovely new asset files are fingerprinted by Propshaft whenever they change, we can afford to just instruct client browsers to cache them for as long as possible, since any new version will have a new file name.
In Cloudflare, rather than just changing the global default from 4 hours, we can add
our own custom rules. So for our Rails assets we can just say for any file ending with
.js
or .css
set the cache-control header to the maximum, which it turns out is
1 year.
From the Cloudflare main menu, select “Caching” and then “Cache Rules” and you will see the form below where we simply select some rules to match - in this case that the URI Path ends with ‘js’ or ‘css’ - and then the caching behaviour we want to apply. In my case I just decided to set to the maximum 1 year.
Result
The result was now my production service was super snappy again. We can also see from the
web inspector that the cache-control
is correctly set, and we can see from the timings
that after our change, the waiting time is 0ms!
Wrap Up
Would love to hear your experiences with caching, or other ideas on optimisation. Don’t hesitate to drop me a note via twitter or any other channels listed here if you have questions, improvements or corrections!