← Recipes

阅读中文版本

Invalidate CDN Cache by Tag

Attach cache tags to origin responses and purge a whole tag group on deploy or data change instead of enumerating every URL and query string.

~30 mincdncachingdeployment

Task

Purge every cached variant of a resource with one API call, without maintaining URL lists or wildcard rules.

When to use this

A product changes price and appears on category pages, search results, and an API endpoint. Purging by URL misses cached variants with different query strings, so stale prices stay visible for hours after the update.

Prerequisites

  • A CDN that supports surrogate keys or cache tags, such as Cloudflare Cache Tags or Fastly
  • An API token with cache purge permission stored in CI secrets
  • Control over origin response headers

Steps

1. Emit a cache tag header that lists every collection the response belongs to.

location /products/ {
  add_header Cache-Tag "product-$arg_id,category-all,deploy-2026-10-21" always;
  add_header Cache-Control "public, max-age=300" always;
  proxy_pass http://127.0.0.1:8080;
}

Expected output: Responses carry Cache-Tag: product-42,category-all,deploy-2026-10-21 and are cacheable for five minutes.

2. Purge the product tag through the CDN API after the price update commits.

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"tags":["product-42"]}'

Expected output: {"success":true,"errors":[],"messages":[],"result":{"id":"..."}}

3. Purge a deploy tag once after a release so every page generated by that build is refreshed.

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/purge_cache" -H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" --data '{"tags":["deploy-2026-10-21"]}'

Expected output: The deploy tag purge returns success and the tag is reused for the next release.

4. Confirm the first request after the purge is a miss and the next one is a hit.

curl -sI https://shop.example.com/products/42 | grep -i -E "cf-cache-status|cache-tag"

Expected output: cf-cache-status: MISS followed by cf-cache-status: HIT on the second request.

Troubleshooting

Problem

The purge API returns 403

Solution

The token needs the Cache Purge permission for the specific zone; zone-level API tokens often lack it by default.

Problem

A tagged response is not purged

Solution

Check that no intermediary strips Cache-Tag and that the tag string matches exactly, including case; tags are case-sensitive.

Limitations

  • Tag-based purge availability and batch limits depend on the CDN plan and provider.
  • Purges propagate across points of presence asynchronously, so a few locations may serve stale content briefly.

Tags beat URL lists

Purging by URL requires knowing every cached variant: query strings, locale prefixes, device-specific paths, and API representations. A cache tag is a label attached to the response that names the data it depends on. One purge call with product-42 invalidates every variant, wherever it was cached, as long as the origin emitted the tag.

Design the tag vocabulary

Keep tags stable and bounded. Use one entity tag per record (product-42), one collection tag per listing (category-all), and one deploy tag per release. Avoid user-specific tags; they explode the tag space and can leak information. Emit tags from a single middleware so every route follows the same convention, and document the vocabulary next to the purge job.

add_header Cache-Tag "product-$arg_id,category-all" always;

Purge at the right moment

Purge after the database commit, not before, or a cache miss may refill with the old value. For deploys, purge the deploy tag once at the end of the release. Batch related tags into one request to stay under provider limits, and log the purge response so failures are visible. If the purge fails, retry with backoff; do not assume the CDN is consistent.

Verify in the right order

Check the cache status header on two consecutive requests. The first should miss and the second should hit. Test with a query-string variant to confirm the tag reaches all representations. Keep an eye on origin request rate after mass purges; a large deploy tag purge can create a thundering herd, so combine it with request coalescing or a short stale window.