The Archivist's Misplaced Folio: On the Disappearing Content of a Cached Fragment

A reader recently asked a question that stopped me in my tracks. They had a simple blog, they said, and had implemented a common performance technique: caching the header and footer as separate HTML files to be pulled in on each page load. It worked beautifully, making the site feel snappy. But then they changed the site's tagline in the header. They updated the cached header file, cleared their server cache, and yet, on some visits, the old tagline would stubbornly reappear. They felt they were going mad, watching words they had deleted flicker back into existence like a ghost. Their question was simple: ‘How is this possible?’

The answer lies in a quiet, often overlooked corner of web performance: the interaction between browser caching and dynamic content assembly. When you break a page into fragments and cache them aggressively, you’re not just storing pieces of HTML. You’re creating a delicate contract between your server, your caching layer, and the user’s browser. The problem our reader encountered is a classic case of a broken contract, where different parties are working from different versions of the agreement.

Imagine you are an archivist assembling a rare manuscript from individual folios stored in separate, locked cabinets. You fetch the ‘header’ folio, the ‘main content’ folio, and the ‘footer’ folio, assembling them into a complete book for a scholar. One day, you update the header folio with a correction. But the clerk who manages the cabinet, eager to be efficient, has decided to keep a copy of the old header folio in their personal satchel. When the next scholar arrives, the clerk, wanting to save time, provides their personal copy. The result is a composite manuscript with a new body and an old, incorrect header. The archivist is baffled; the cabinet contains the right version, yet the wrong one persists.

This is precisely what happens in the browser. Your server may be serving the correct, updated header fragment. But a user’s browser, in its zeal for speed, might be serving an older, cached version of that same fragment from its local storage. This is especially likely if the cache headers for that fragment are set to a long expiry time, telling the browser ‘hold on to this for a year, it won’t change.’ When the browser constructs the page, it uses the stale fragment it already has, blissfully unaware that the central copy has been revised.

The solution isn't to abandon caching, which is a cornerstone of performance. It’s to manage the invalidation of these caches with intention. A common and effective strategy is ‘cache busting’ by adding a unique identifier to the fragment’s URL, often a version number or a hash of its content. When you update the header, the URL changes (e.g., from header-v1.html to header-v2.html). The browser, seeing a brand new URL, has no choice but to fetch the fresh copy. It’s like the archivist telling the clerk, ‘Throw away the folio in your satchel; we are now using the one from the blue cabinet, not the red one.’ The contract is reset, and consistency is restored.

It’s a reminder that performance is not just about speed, but about reliable speed. A fast experience that serves stale or broken content is a hollow victory. The craft lies in designing systems where performance and freshness coexist, ensuring that when you update a word, it stays updated for everyone, banishing the digital ghosts of content past.

Notes & further reading

A few pages I came back to while writing this: