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.com shows cf-cache-status: HIT with old content
  • Content is updated in some regions but stale in others
  • curl from different geographic locations returns different content versions
  • Purge API returns 200 OK but 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. 1.Verify the purge actually completed:
  2. 2.```bash
  3. 3.# Check the purge request status via API
  4. 4.curl -s "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache?status=all" \
  5. 5.-H "Authorization: Bearer API_TOKEN"
  6. 6.`
  7. 7.Test cache status from multiple locations:
  8. 8.```bash
  9. 9.# Check cf-cache-status header
  10. 10.curl -sI https://example.com/path | grep cf-cache-status
  11. 11.# HIT = served from cache (may be stale)
  12. 12.# MISS = fetched from origin (should be fresh)
  13. 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. 1.Force a complete cache purge:
  2. 2.```bash
  3. 3.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  4. 4.-H "Authorization: Bearer API_TOKEN" \
  5. 5.-H "Content-Type: application/json" \
  6. 6.--data '{"purge_everything": true}'
  7. 7.`
  8. 8.Purge specific files with cache busting:
  9. 9.```bash
  10. 10.# Purge individual files
  11. 11.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  12. 12.-H "Authorization: Bearer API_TOKEN" \
  13. 13.-H "Content-Type: application/json" \
  14. 14.--data '{"files": ["https://example.com/style.css", "https://example.com/app.js"]}'
  15. 15.`
  16. 16.Use cache tags for targeted purging:
  17. 17.```bash
  18. 18.# Purge by tag (if your origin sets Cache-Tag headers)
  19. 19.curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/purge_cache" \
  20. 20.-H "Authorization: Bearer API_TOKEN" \
  21. 21.-H "Content-Type: application/json" \
  22. 22.--data '{"tags": ["frontend", "api-v2"]}'
  23. 23.`
  24. 24.Verify the fix by bypassing Cloudflare cache:
  25. 25.```bash
  26. 26.# Add Cache-Control: no-cache header to force origin fetch
  27. 27.curl -H "Cache-Control: no-cache" -I https://example.com
  28. 28.# Should show cf-cache-status: DYNAMIC or MISS with fresh content
  29. 29.`

Prevention

  • Use purge_everything for 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-age headers on the origin to control staleness
  • Monitor cache hit ratios per geographic region in Cloudflare Analytics