You deploy a new version of your JavaScript bundle. Users on cached CDN nodes still see the old version. CDN cache invalidation is how you force cached content to be replaced before its TTL expires. It’s more complex than database cache invalidation because the content lives in hundreds of PoPs around the world that must all be notified.

Why CDN Invalidation Is Hard#

Cache invalidation in a single Redis instance: delete the key. Done. CDN invalidation: send an invalidation request to a central control plane, which fans it out to 300+ PoPs, each of which must purge the cached object from local storage. The fan-out itself takes time (seconds to minutes), and PoPs may miss the invalidation if they’re temporarily unreachable.

Invalidation by URL#

The simplest approach: purge a specific URL. DELETE /cache/https://cdn.example.com/app.js. The CDN control plane sends this purge request to all PoPs. Each PoP deletes the cached copy. Next request to that URL fetches fresh from origin.

Latency: Cloudflare claims 150ms for global purge propagation. Fastly targets under 150ms. AWS CloudFront is slower: up to 10 minutes per their documentation, typically faster in practice.

Surrogate Keys / Cache Tags#

Purging by URL one at a time doesn’t scale for bulk invalidation. If you need to purge all content related to a product (product page, images, API responses), you’d need to track and purge dozens of URLs.

Surrogate keys (Fastly) or cache tags (Cloudflare) let you tag cached objects with arbitrary labels at cache time. The response header Surrogate-Key: product:123 tags the response. Purging product:123 instantly invalidates all cached objects with that tag across all PoPs. One purge request, N objects invalidated.

graph TD A[Deploy new product image for product 123] --> B[Send purge: tag=product:123] B --> C[CDN control plane: fan-out purge to all PoPs] C --> D[Tokyo PoP: delete all objects tagged product:123] C --> E[Frankfurt PoP: delete all objects tagged product:123] C --> F[São Paulo PoP: delete all objects tagged product:123] D --> G[Next request: cache miss, fetch fresh from origin] E --> G F --> G style A fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style B fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style C fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style D fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style E fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style F fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff style G fill:#000000,stroke:#00ff00,stroke-width:2px,color:#fff

Cache Busting as the Better Alternative#

Invalidation is reactive: you update content, then invalidate the old cached version. Cache busting is proactive: include a content hash in the URL. /app.abc123.js caches with long TTL (1 year). When you deploy new code, the URL changes to /app.def456.js. No invalidation needed; the old URL simply stops being requested.

Cache busting works for versioned assets (JS, CSS, images with build hashes). It doesn’t work for URLs that must be stable (API endpoints, product pages, canonical URLs). Those require invalidation.

Stale-While-Revalidate#

An alternative to invalidation: use Cache-Control: stale-while-revalidate=86400. The CDN serves the stale cached response immediately while asynchronously fetching a fresh version from origin. Users get fast responses even during content updates; fresh content propagates within the revalidation window. No explicit invalidation needed.

At Oracle#

Oracle Cloud Object Storage with CDN used content-hash-based URLs for static assets and surrogate keys for API responses. When a customer updated their Oracle Database documentation, we tagged all cached pages for that doc version with doc:v19c. On update, one purge request cleared all 847 related cached responses across all PoPs in under 2 seconds. Without surrogate keys, we’d have needed to track and purge 847 individual URLs.

What I’m Learning#

CDN cache invalidation is a global fan-out operation with non-trivial propagation latency. Cache busting sidesteps invalidation entirely for versioned assets. Surrogate keys make bulk invalidation practical. Stale-while-revalidate eliminates the need for invalidation in many cases by accepting brief staleness.

Have you had a CDN cache invalidation strategy that failed during a critical deployment, and what did you change?