Introduction
When you purge the cache in Cloudflare, the invalidation request must propagate to all 300+ edge locations worldwide. While most edge locations purge within seconds, some may take up to 48 hours depending on the purge method, edge location health, and cache tier configuration. During this window, users in certain geographic regions see stale (old) content while others see the updated version, causing inconsistent user experiences.
Symptoms
- Cache purge completed but some users still see old content
curl -I https://example.comshowscf-cache-status: HITwith old content- Content is updated in some regions but stale in others
curlfrom different geographic locations returns different content versions- Purge API returns
200 OKbut cache is not actually cleared at all edges
Common Causes
- Using single-file purge instead of purge-everything (only purges specific URLs)
- Edge location temporarily unreachable during purge propagation
- Cache tier configuration causing stale content from parent edge
- Browser or ISP cache still holding old content (not a Cloudflare issue)
- CDN cache key variations (query strings, cookies) not covered by the purge
Step-by-Step Fix
- 1.Verify the purge actually completed:
- 2.```bash
- 3.# Check the purge request status via API
- 4.curl -s "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache?status=all" \
- 5.-H "Authorization: Bearer API_TOKEN"
- 6.
` - 7.Test cache status from multiple locations:
- 8.```bash
- 9.# Check cf-cache-status header
- 10.curl -sI https://example.com/path | grep cf-cache-status
- 11.# HIT = served from cache (may be stale)
- 12.# MISS = fetched from origin (should be fresh)
- 13.# DYNAMIC = not cached
# Use different DNS resolvers to hit different edge locations dig example.com @8.8.8.8 +short dig example.com @1.1.1.1 +short # These may resolve to different Cloudflare edge IPs ```
- 1.Force a complete cache purge:
- 2.```bash
- 3.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
- 4.-H "Authorization: Bearer API_TOKEN" \
- 5.-H "Content-Type: application/json" \
- 6.--data '{"purge_everything": true}'
- 7.
` - 8.Purge specific files with cache busting:
- 9.```bash
- 10.# Purge individual files
- 11.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
- 12.-H "Authorization: Bearer API_TOKEN" \
- 13.-H "Content-Type: application/json" \
- 14.--data '{"files": ["https://example.com/style.css", "https://example.com/app.js"]}'
- 15.
` - 16.Use cache tags for targeted purging:
- 17.```bash
- 18.# Purge by tag (if your origin sets Cache-Tag headers)
- 19.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
- 20.-H "Authorization: Bearer API_TOKEN" \
- 21.-H "Content-Type: application/json" \
- 22.--data '{"tags": ["frontend", "api-v2"]}'
- 23.
` - 24.Verify the fix by bypassing Cloudflare cache:
- 25.```bash
- 26.# Add Cache-Control: no-cache header to force origin fetch
- 27.curl -H "Cache-Control: no-cache" -I https://example.com
- 28.# Should show cf-cache-status: DYNAMIC or MISS with fresh content
- 29.
`
Prevention
- Use
purge_everythingfor major deployments rather than selective file purges - Implement cache-busting versioning in asset URLs (
style.v2.css) - Use Cloudflare Cache Tags for more granular cache invalidation
- Set appropriate
Cache-Control: max-ageheaders on the origin to control staleness - Monitor cache hit ratios per geographic region in Cloudflare Analytics