Engineering

A deploy is not one moment: what a stale stylesheet taught us about caching

We shipped a new design and one data centre served the old stylesheet under the new address, with a cache set to keep it there for a week. The cache-busting was correct. The assumption underneath it was not.

Most static sites cache-bust the same way: keep the file name, add a version to the address, styles.css?v=abc123. Change the file, change the version, and every browser is forced to fetch the new one. We did exactly that, and on a normal day it works.

On the day it did not, a visitor in one region saw the new page markup with the old stylesheet. Nothing was broken in the code. The new page asked for styles.css?v=new, the request reached a data centre that was still serving the previous deployment, and that data centre answered with the file it had: the old styles.css. The edge cache then stored that answer under the new address, for seven days, because that is what we had told it to do with versioned files. It would have stayed wrong in that region for the week had we not purged that one address by hand.

Cloudflare documents the cause. A Pages deployment is immutable, but rolling it out across the network is not instant, and for a while some locations can still serve the previous version. A query string cannot protect you from that, because the old deployment does have a file called styles.css. It simply ignores the part after the question mark.

The fix was to put the version in the file name instead: styles.3f9a1c2b7e.css, built from a hash of the file's contents. An old deployment has no file by that name, so it cannot answer with the wrong bytes. It can only say it does not exist. We added one small rule at the edge for that case: when a hashed file is missing, serve the current unversioned file with caching switched off. A visitor caught mid-rollout may see the previous stylesheet for that one load, but nothing wrong is stored, so the next load is right.

The build now fails if any page refers to a stylesheet or script without a hash, or with a version query, so the old pattern cannot come back by accident. Images and fonts keep stable names on purpose, so they keep the risk: if a replaced image is served stale, we purge that one address.

The general lesson is not about one provider. Any system that rolls out gradually, a CDN, a fleet of servers or an app store, has a window where old and new run side by side. Design so that the old version cannot answer a question only the new version should understand.

All insights

Let's scope your project.

Tell us how your business needs to operate. We'll send a clear, no-obligation quote.