A year in the cache, for a file whose address changes when it does
Every script and stylesheet we ship carries its version in its address, so a browser could keep it for a year. Ours were told to re-check every one on every page — 138 questions per screen with the same answer. One file fixed it, and it created a rule we now cannot break.
Open a back-office screen, then another, and count what the browser asks the server. We counted: a hundred and thirty-eight scripts and two stylesheets, and on every navigation the browser asked about every one of them. "Has this changed?" A hundred and thirty-eight times. The answer was always no.
The reason was a default. The platform that serves our files marks everything
re-check every time unless told otherwise, and nobody had told it
otherwise. Which was odd, because we had already solved the problem the
re-check exists for. Every script and stylesheet we ship is referenced with its
version in the address — app.js?v=5.723.0 — and the version moves
with every release. A file at that address can never change. If the file
changes, so does the address. So the browser could have kept every one of them
for a year and never been wrong.
The fix is a file
One text file beside the assets, five rules long. Scripts and stylesheets: keep for a year, immutable. The service worker: re-check every time, because an old worker kept for a year would keep serving an old till. Screenshots and brand images, which have no version in their address: a day, then refresh in the background. Measured on one back-office screen, the requests that reached the network per load went from a hundred and thirty-eight to none, and the screen's own time from about four hundred milliseconds to under two hundred. A first-ever visit still fetches everything once. Every page after it does not.
The rule it creates
A year-long cache has one condition: the address must change whenever the file does. We had the version stamp; we had not had the discipline, because nothing enforced it. The day before this change, a one-line fix to a script had been re-uploaded under the same version — harmless then, because every browser re-checked. Under the new rule that same fix would never reach a browser that already held the file. So the rule is now written down where the deploy steps live, and a test reads the shells for any script or stylesheet referenced without a version. An edit to anything in those folders bumps the version, even a hotfix, even a comma.
There is a general shape in this. A default that says "re-check every time" is the safe choice for a thing that might change under the same name. It is pure cost for a thing whose name changes with it. Knowing which one you have is the whole decision.