Back to Blog
PerformanceJune 23, 20265 min read

Edge Caching with Surrogate Keys for Precise Cache Invalidation

Edge Caching performance relies on smart invalidation. Learn how to use Surrogate Keys to purge specific content without clearing your entire CDN cache.

Edge CachingCDNWeb PerformanceCache InvalidationSurrogate KeysPerformanceWeb VitalsFrontend

Last month, we pushed a site update that should have taken seconds to propagate. Instead, our global cache purge triggered a massive database spike, slowing the site to a crawl for about 15 minutes while the origin re-warmed. It was a classic "all-or-nothing" invalidation failure, and it forced us to rethink how we handle Edge Caching at the infrastructure level.

If you’re still relying on global PURGE requests or blanket TTL resets, you’re likely hurting your own performance. When you clear everything, you lose the benefits of your warm cache, forcing users to wait while your origin server handles a flood of re-computation requests.

The Problem with Global Purging

Most developers start with simple TTL-based caching. You set a cache-control header, the CDN respects it, and life is good until the content changes. When it does, you purge the URL. But what happens when that one piece of data—say, a product price—is embedded in 50 different pages?

Purging the URL for the product page isn't enough. You either end up with stale data on the category pages or you clear the entire cache, which is what I call the "nuclear option." This is where Surrogate Keys (often called Cache Tags) change the game.

How Surrogate Keys Work

Surrogate keys allow you to associate multiple cacheable objects with a single "tag." When that tag is invalidated, the CDN automatically purges every object associated with it.

Think of it like a database index. Instead of scanning the entire table (the whole cache), you only target the rows that matter.

  1. Tagging: When the origin sends a response, include a custom header: Surrogate-Key: product-123 category-electronics.
  2. Storage: The CDN stores the object and maps it to those keys.
  3. Invalidation: Send a PURGE request to the CDN API for product-123. The CDN instantly drops only the objects tagged with that key.

We first tried implementing this using a custom middleware in our Next.js stack, but we hit a snag with Next.js App Router Data Revalidation: Mastering Cache Tags at Scale. We initially tried to manage tags in the application layer, which resulted in a race condition where the tag header wasn't being set before the CDN intercepted the response. It taught us that tagging must happen at the closest point to the origin's response pipeline.

Implementing Granular Invalidation

To make this work, your CDN provider (Fastly, Cloudflare, or Akamai) must support Surrogate-Key headers. Here is a simplified example of how we handle this in a Node.js-based backend:

JAVASCRIPT
// Middleware example to inject surrogate keys
app.use((req, res, next) => {
  // Logic to determine which tags apply to this request
  const tags = getTagsForPath(req.path); 
  
  // Set the header so the CDN knows how to group this object
  res.setHeader(CE9178">'Surrogate-Key', tags.join(CE9178">' '));
  next();
});

When a content editor updates a product, we trigger an API call to the CDN:

Bash
curl -X PURGE "https://api.cdn.com/purge" \
     -H "Surrogate-Key: product-123" \
     -H "Fastly-Key: YOUR_API_TOKEN"

This approach is significantly more efficient than the strategies discussed in Next.js Cache Invalidation: Mastering Cross-Region Strategies, because it doesn't require the application to know the full URL structure of the site. It only needs to know the ID of the data that changed.

The Trade-offs and Gotchas

Is this a silver bullet? Not exactly.

The biggest risk is "key explosion." If you create a unique tag for every single user session or every permutation of a page, you'll bloat your CDN's metadata storage. We keep our tags coarse-grained—by entity type or category—to avoid this.

Also, testing Cache Invalidation in local environments is notoriously difficult because standard browsers don't behave like global edge networks. We ended up building a small mock-CDN proxy using nginx in our Docker dev environment to verify that the headers were being passed correctly before pushing to production.

When to Use Surrogate Keys

You should look into this if:

  • You have a high-traffic site where a cache miss causes a noticeable spike in origin latency.
  • Your content is highly relational (e.g., one update changes dozens of pages).
  • You are tired of "stale data" tickets from your content team.

If you are working with older architectures, you might find that WordPress Performance: Implementing Redis Persistent Object Caching provides a better starting point for object-level control. However, once you move to a distributed edge architecture, surrogate keys are the only way to maintain high hit rates.

Frequently Asked Questions

Does this increase my CDN bill? Generally, no. Most major CDNs include surrogate key support in their standard tiers. You pay for the storage of the objects, not the tags themselves.

What happens if I purge a tag that doesn't exist? Nothing. Most CDNs treat a purge request for a non-existent key as a no-op. It’s safe to send purge requests even if you aren't 100% sure the content is cached.

How do I debug tag associations? Use curl -I to inspect the response headers. If you don't see the Surrogate-Key header, the CDN won't know what to purge.

I’m still not entirely convinced we’ve optimized our tag granularity perfectly. Sometimes we over-purge by including too many pages in a single tag, which leads to unnecessary cache misses. Next time, I think we’ll implement a more dynamic tagging system that calculates dependencies based on the actual components rendered on the page, rather than just the primary data entity. It’s a work in progress, but it beats the nuclear option any day.

Similar Posts