Surrogate Key / Cache Tag
A label attached to cached responses that allows purging all content with that label, regardless of URL. Set via response header (e.g., Surrogate-Key or Cache-Tag). When you purge the tag, all responses carrying that tag are invalidated.
Full Explanation
Surrogate keys (also called cache tags) let you label cached responses with arbitrary tags so you can purge groups of related content without knowing every individual URL. A single response can carry multiple tags. For example, a product page might be tagged with product-123, category-shoes, and homepage-featured. When the product price changes, you purge the tag product-123 and every cached URL carrying that tag gets invalidated instantly.
This solves a real problem. Without surrogate keys, you would need to track every URL that displays a given product and purge them one by one. That is fragile and slow. With tags, your application just tags responses as it generates them, and your purge logic only needs to know the tag name.
Different CDN providers use different header names for this feature. Fastly uses Surrogate-Key, Cloudflare uses Cache-Tag, and Akamai uses Edge-Cache-Tag. The concept is the same across all of them: space-separated or comma-separated tags in a response header, with a purge API that accepts tag names.
// Response with surrogate keys (Fastly format)
HTTP/1.1 200 OK
Content-Type: text/html
Surrogate-Key: product-123 category-shoes homepage-featured
Cache-Control: max-age=86400
// Same concept, Cloudflare format
HTTP/1.1 200 OK
Cache-Tag: product-123,category-shoes,homepage-featured
Interactive Animation
Examples
Here is how you would tag responses in your application and then purge by tag using Fastly's API.
# Django middleware to add surrogate keys
class SurrogateKeyMiddleware:
def process_response(self, request, response):
if hasattr(request, '_surrogate_keys'):
response['Surrogate-Key'] = ' '.join(request._surrogate_keys)
return response
# In your view
def product_detail(request, product_id):
product = Product.objects.get(id=product_id)
request._surrogate_keys = [
f'product-{product.id}',
f'category-{product.category.slug}',
]
return render(request, 'product.html', {'product': product})
# Purge by tag via Fastly API
curl -X POST https://api.fastly.com/service/SVC_ID/purge/product-123 \
-H "Fastly-Key: YOUR_API_TOKEN"
# All URLs tagged with "product-123" are now invalidated
Frequently Asked Questions
A label attached to cached responses that allows purging all content with that label, regardless of URL. Set via response header (e.g., Surrogate-Key or Cache-Tag). When you purge the tag, all responses carrying that tag are invalidated.
Here is how you would tag responses in your application and then purge by tag using Fastly's API.
# Django middleware to add surrogate keys
class SurrogateKeyMiddleware:
def process_response(self, request, response):
if hasattr(request, '_surrogate_keys'):
response['Surrogate-Key'] = ' '.join(request._surrogate_keys)
return response
# In your view
def product_detail(request, product_id):
product = Product.objects.get(id=product_id)
request._surrogate_keys = [
f'product-{product.id}',
f'category-{product.category.slug}',
]
return render(request, 'product.html', {'product': product})
# Purge by tag via Fastly API
curl -X POST https://api.fastly.com/service/SVC_ID/purge/product-123 \
-H "Fastly-Key: YOUR_API_TOKEN"
# All URLs tagged with "product-123" are now invalidated