You change a stylesheet, refresh, and it looks right. A customer opens the site and sees the old one. You ask them to clear their cache, they do, and it works. Next time you change something, the same sequence repeats.
This is not the customer’s problem. It is a step the website is missing.
Why it happens
Browsers store stylesheets, scripts and images locally for speed. On a later visit to the same address they use the stored copy rather than asking the server.
The key point is that a browser decides whether something is the same file by looking at the address.
Your stylesheet is at /assets/style.css. You changed its contents and the address did not change. As far as the browser is concerned this is the file it already holds, and there is nothing to fetch.
A CDN may sit in between doing the same thing, usually for longer.
So the situation becomes: the server has the new file, the CDN has the old one, the customer’s browser has the old one, and you — having purged your own cache repeatedly while working — see the new one. You have no way of knowing what anyone else sees.
The fix: make the address follow the content
The idea is simple — when the content changes, change the address. Neither the browser nor the CDN has seen the new address, so both must fetch it.
Two common approaches:
1. A version parameter on the address.
/assets/style.css becomes /assets/style.css?v=1712345678, where the number is generated from the file’s modification time. Edit the file and the number changes, so the address changes.
Simple to implement and the filename is untouched. Our own site uses this, taking the value from the file’s timestamp so nobody has to remember anything.
2. A content hash in the filename.
/assets/style.a3f9c2.css, where the middle portion is computed from the contents. Change the content and the hash changes, so the filename changes.
More thorough, and safer with some CDNs — a misconfigured one may ignore query parameters, which defeats the first approach, while a different filename cannot be ignored.
We use this for font files, since fonts are referenced from a stylesheet at a fixed path where modification times do not help.
What matters is that it is automatic
The mistake here is not choosing the wrong method. It is whether the version updates by itself.
Plenty of sites write versions by hand: ?v=2, changed to ?v=3 after an edit. This works for about a month and then starts being missed — under time pressure, or because the file was edited and the version forgotten.
And what a miss looks like is “some users see the old version”, which you cannot detect from your own machine.
Any step depending on someone remembering will eventually be forgotten. The version has to come from the build process or the software itself. There is no other reliable arrangement.
Checking your own site
Thirty seconds:
Open your site, view page source, find the line referencing your stylesheet, and look at it:
href="/style.css" — no version, so this problem is present.
href="/style.css?ver=6.4.3" — a version, but if that is a platform version number, it changes only when the platform upgrades, not when you edit styles, which is the same as having none.
href="/style.css?ver=1712345678" or href="/style.a3f9c2.css" — correct.
Then verify: change something, redeploy, and check whether the value moved. If it did, it is automatic.
Doing it properly saves something else
Versioning has a benefit many sites never claim.
Since any change produces a new address, these files can carry very long cache durations — a year, or marked as never changing. A stale address does not matter when a change produces a different one.
A returning visitor then reuses the stylesheet, scripts and fonts locally, downloading nothing. For repeat visitors that is a real improvement.
Without versioning you cannot risk it: set it long and changes never arrive, set it short and everything is revalidated constantly. Versioning is what makes long caching safe.
One trap we hit is worth mentioning. When configuring cache rules, if a catch-all rule and a specific asset rule both match the same files, some systems concatenate the values rather than replacing them. The assets went out carrying both “cache for ten minutes” and “cache for a year”, with the first taking effect — so the year-long policy did nothing, and nothing reported an error.
Only one thing finds that: actually reading the response headers rather than trusting what a configuration screen says.
Images too
The same problem applies to images and is harder to spot.
You replace a product photograph, keeping the filename, and upload over the old one. It looks new to you because you just uploaded it; customers keep seeing the previous image, possibly for days.
Same remedy: a new image gets a new filename. Do not overwrite.
A related trap: CDNs cache 404s. If someone or a crawler requests an image address before the file is uploaded, the CDN records that nothing is there. You upload it and visitors still see nothing.
We have hit this twice. Identify it by adding a random parameter to the image address — if that displays, it is caching rather than a missing file.
In one sentence
If your process includes “ask the customer to clear their cache”, that is not a normal step, it is an unsolved technical problem.
On a properly configured site you deploy, and everyone’s next visit is current, without anybody doing anything.
On our projects asset versions are generated automatically — modification time for styles and scripts, content hash for fonts. Not a feature, baseline configuration, because omitting it produces problems continuously.