Invalidate the HTML cache next to your mutations
· 2 min read
JSkelet’s HTML cache makes public pages feel static-fast. It also creates a classic consistency problem: the database moved, the warm HTML did not. The fix is not “turn the cache off.” The fix is naming keys beside mutations.
The contract
- Render functions for a path are safe to re-run.
- Cache keys follow public URLs (including locale prefixes when you use them).
- Mutations call
invalidateHtmlCachefor every public path whose HTML embeds the changed data. - Private routes never enter the public cache.
If step 3 is missing, editors will swear the framework is broken.
Minimum invalidation sets
For a blog post save:
- The post detail URL
- The blog index
- Any tag/category URLs that include the post
- Locale alternates of the above, if those pages are cached separately
For a global nav change in layout context:
- Either accept TTL expiry, or invalidate a known set of top landing pages, or keep nav in a fragment strategy you control deliberately
Start precise. Broaden only when you measure staleness tickets.
Soft stale vs hard correctness
Stale-while-revalidate is excellent for brochure traffic. It is the wrong mental model for “show me my edit in the same tab immediately” unless you invalidate first. After invalidation, the next GET should miss (or soft-miss) and warm authoritative HTML.
Communicate that to editors in one sentence: save updates storage immediately; public HTML updates on the next warm after invalidation.
Multi-instance notes
In-process memory caches do not sync themselves across replicas. JSkelet documents shared cache options when you need them. Invalidation APIs should target the same keyspace your shared layer uses. Deploying without that story produces “works on node A” incidents.
Debugging checklist
- Did the mutation commit?
- Which keys were invalidated (log them in dev)?
- Are you comparing a CDN layer in front of Node?
- Is the browser showing bfcache rather than a server miss?
- Did you invalidate
/blogbut forget/tr/blog?
Anti-patterns
- Flushing the entire cache on every typo fix
- Caching
private: trueresponses “just for speed” - Invalidating in a cron “eventually” while promising instant publish
- Encoding user-specific HTML into public keys
Treat invalidation as part of your domain API — publishPost() should own both persistence and cache keys. That is how JSkelet apps stay fast without lying to editors.
Comments
No comments yet.