Cache Busting FAQ
Common questions about Freestruct's cache busting system
Why do I need this? My site is already built.
Every time you deploy, your SSG (Jekyll, Hugo, Docusaurus) generates fresh HTML. But here’s the painful truth:
- CDNs cache at the edge - CloudFlare, Fastly, CloudFront all cache your HTML
- Browser caches are aggressive - Users may have locally cached your site
- Intermediate proxies - ISPs, corporate networks all cache
You rebuild your docs. Deploy. But users still see old content. You check the CMS/SSG - it says deployed. You check the CDN - it says everything is fine. But your user in Berlin is still seeing last week’s version.
This is the “I’m so fucking sick of this” moment.
Freestruct solves this by injecting a unique hash into every build. The HTML is different. CDNs must re-fetch. Browser cache is bypassed via query params.
Why can’t I just use Cache-Control headers?
You can! But there’s a catch:
- Meta Cache-Control tags are ignored by most CDNs - They only respect HTTP headers
- Setting headers requires server access - Not possible with GitHub Pages, Netlify basic, etc.
- Aggressive CDNs ignore everything - CloudFlare’s “Cache Everything” page rule doesn’t care about your meta tags
The hash approach works because it changes the actual content. The CDN sees a new URL/HTML and can’t serve its cache.
What’s the difference between the meta tag and canonical URL?
Two mechanisms for different layers:
-
<meta name="freestruct-build">- For debugging and verification. Shows which build is deployed. -
?v=query param on canonical - This is the real cache buster. When a CDN sees a new URL, it treats it as new content.
Both are generated automatically. You don’t need to do anything.
Will this break my existing SEO?
No. It improves it:
- Canonical URLs with
?v=are still valid canonicals - Search engines understand versioned URLs
- The hash changes every build, but that’s intentional - you want everything fresh
My CDN already has auto-purge. Why do I need this?
Great! If your CDN properly purges on every deploy, you’re lucky. But:
- Many setups don’t - GitHub Pages + CloudFlare needs manual purge
- Purge can fail silently - API errors, rate limits, misconfigured zones
- Intermediate caches - Proxies, CDNs in front of your CDN
- Stale references - If any external site links to your old
?v=version
The hash is your safety net. Even if purge fails, the new HTML breaks the cache.
Does this work with GitHub Pages?
Yes! This is actually why we built it:
- GitHub Pages has no cache control
- GitHub’s CDN can be slow to propagate
- Custom domains via CloudFlare need manual purge
With freestruct, every commit automatically busts caches. No manual purge needed.
Does this work with Netlify/Vercel?
Yes! Both have their own CDNs:
- Netlify: May need asset pruning, hash helps
- Vercel: Edge caching is aggressive, hash ensures freshness
What if I don’t configure purge hooks?
The hash still works!
Without purge hooks configured:
- Every build generates a new hash
<meta name="freestruct-build">is injected- Canonical URLs get
?v={hash} - CDNs see different content (different HTML fingerprint)
- Browser caches are bypassed
You get ~80% of the benefit automatically. Purge hooks are the bonus for aggressive cache layers.
Can the hash collide? What if two builds have the same hash?
The hash is SHA1 of JSON.stringify(config) + timestamp. The timestamp is Date.now() in milliseconds. Collisions are practically impossible unless you:
- Run two builds in the same millisecond
- With identical config
Even then, it’s not a security issue - just means the same hash for two builds. Very unlikely.
Can I disable the hash?
Yes, but why would you? Add to config:
cacheBusting:
hash: false
We don’t recommend this. The hash is what makes cache busting work.
Does this work with SSGs other than Jekyll?
Yes! Freestruct is completely agnostic:
- Jekyll -
docs/_siteoutput - Hugo -
public/output - Docusaurus -
build/output - Gatsby -
public/output - Any SSG - Just point
outputDirto your build folder
The hash injection happens after your SSG finishes. It doesn’t care what generated the HTML.
Will this slow down my builds?
Negligibly. The hash generation and injection adds ~10-50ms per page. For a typical docs site with 50-100 pages, that’s under 5 seconds total.
Can I use different hashes for different environments?
Yes! The hash includes your entire config. If you have:
# Production
site:
url: https://docs.example.com
# Staging
site:
url: https://staging.example.com
Each environment gets its own hash. Perfect for CI/CD pipelines with multiple environments.
What’s the difference between freestruct’s cache busting and asset hashing?
SSGs often hash static assets (JS, CSS, images) with filenames like app.a1b2c3d4.js. This is great but:
- Only covers assets - Not the HTML
- Requires SSG support - Not all SSGs do this well
- Doesn’t help CDN HTML cache - The HTML is still cached
Freestruct complements asset hashing by handling the HTML layer. Use both together for maximum cache control.
My site still shows old content. What do I do?
- Check the hash - View page source, look for
freestruct-build - Hard refresh - Ctrl+Shift+R (or Cmd+Shift+R)
- Incognito mode - Test in a fresh browser
- Check CDN dashboard - Look for purge status
- Wait - Some CDNs take 5-30 minutes to fully propagate
If all else fails, manually purge your CDN cache. The hash is your backup - even with stale CDN cache, the next deploy will fix it.
Is this secure? Can someone manipulate the hash?
No security concerns:
- Hash is internal - Generated at build time, injected into HTML
- No security implications - It’s just a version identifier
- Doesn’t expose config - Only the hash travels with the page
I want to test this. How do I verify it’s working?
- Deploy your site
- View page source
- Look for
<meta name="freestruct-build" content="..."> - Note the hash
- Make a small change to any page
- Rebuild and deploy
- Check again - the hash should be different
- Check canonical URL has new
?v=parameter
You’ll see the hash change every single deploy.
Still have questions?
This is a pain we’ve all felt. If your specific scenario isn’t covered, open an issue. We built this because we were tired of “why isn’t my docs updating” at 2am.