Field Notes
All posts

Cache invalidation strategies that scale

Purge by URL, purge by tag, or never purge at all. Choosing well depends on how your content changes.

The hard problem

Caching makes sites fast. Invalidation keeps them correct. The two pull in opposite directions: the longer a response stays cached, the faster and cheaper it is to serve, and the longer a visitor might see something out of date.

Strategy one: short lifetimes

The simplest approach avoids explicit invalidation entirely. Cache responses for a short time, perhaps thirty seconds or a minute, and accept that changes take that long to appear. Combined with stale-while-revalidate, visitors almost never wait for a fresh render.

This works well for content where a brief delay is acceptable and traffic is high enough that the cache stays warm.

Strategy two: purge by URL

When content changes, send a purge request for every URL that displays it. This is precise but hard to get right, because content appears in many places. A blog post shows up on its own page, on the index, on the home page, in a category listing, in an RSS feed, and in a sitemap. Missing any of them leaves a stale copy.

Strategy three: purge by tag

Many CDNs let you attach tags to cached responses, often through a response header listing identifiers. The page for a post is tagged with that post's ID; the index page is tagged with every post ID it shows. When a post changes, one purge request for its tag clears every response that included it.

Tag-based purging scales well because the relationship between content and pages is recorded at render time, by the code that actually knows which content it used.

Strategy four: versioned URLs

For assets, the best invalidation is none. Put a content hash in the filename, cache it forever, and change the reference when the content changes. This does not work for HTML, whose URLs must remain stable, but it removes assets from the invalidation problem completely.

Strategy five: render fresh, cache the data

Another approach is to never cache HTML at all and instead cache the data the page reads. Every page view renders, but the content requests it makes are served from a nearby cache with short lifetimes or tag-based purging. Pages stay correct to within seconds, and the expensive part of the work, fetching content, stays fast.

Choosing

  • High traffic, tolerant of delay: short lifetimes.
  • Editorial content with clear relationships: tags.
  • Static assets: versioned URLs.
  • Personalized or rapidly changing pages: render fresh and cache the data underneath.

Most real sites combine several. The important thing is to choose deliberately and to test that a change actually appears everywhere it should.