# Cloudflare CDN & Caching
+
+Cache strategies for global delivery — Cloudflare CDN, Vercel Edge/Runtime Cache, stale-while-revalidate patterns, and cache invalidation architectures.
+
+## Recent changes (2026)
+
+- Cloudflare Gen 13 servers (Mar 2026) prioritize higher core counts and edge compute throughput; the network team traded large per-core L3 cache for raw cores and mitigated latency with a new FL2 stack. This reinforces Cloudflare's push toward compute-heavy edge workloads (Workers, RAG, inference) while keeping HTTP caching features intact: https://blog.cloudflare.com/gen13-launch/ (2026-03-23).
+
+- Cloudflare research and engineering have called out the rise of AI-bot traffic and how it changes cache dynamics (Apr 2026). Automated agents request high volumes, often touching low-popularity pages and causing cache pollution and eviction of hot human-facing content. Site operators should consider bot-aware cache designs, targeted invalidation, and rate- limiting/crawl controls: https://blog.cloudflare.com/rethinking-cache-ai-humans/ (2026-04-02).
+
+- Vercel introduced (Mar 2026) Runtime Cache: a regional, ephemeral, tag-aware cache for functions and server runtime (not a replacement for CDN cache). Use Runtime Cache for reusing expensive computation and DB queries within a region; continue to use CDN (Vercel CDN or Cloudflare) for full HTTP response caching: https://vercel.com/docs/caching/runtime-cache (last updated 2026-03-05).
+
+- Cloudflare's cache purge API and tag-based purge features remain the recommended mechanism for targeted invalidation. See Cloudflare Cache docs for exact rate limits and headers (notably, Cloudflare strips Cache-Tag headers before sending responses to clients): https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-tags/ and https://developers.cloudflare.com/cache/how-to/purge-cache/.
−Cache strategies for global delivery — Cloudflare CDN, Vercel Edge Cache, stale-while-revalidate patterns, and cache invalidation architectures.
## When to use
- Serving static assets (JS, CSS, images, fonts) from edge PoPs worldwide
- Caching API responses that don't change on every request
−- Implementing stale-while-revalidate for near-instant page loads
+- Implementing stale-while-revalidate (SWR) for near-instant page loads
- Reducing origin load by serving cached content at the edge
+- Protecting origins from spikes (CDN absorption)
−- Protecting origins from traffic spikes with CDN absorption
+- A/B testing and personalization with carefully scoped cache variants
−- A/B testing and personalization with edge-side cache variants
- Image optimization and format negotiation (WebP, AVIF) at the edge
## When NOT to use
- Real-time data that must be fresh on every request (WebSocket feeds, live scores)
+- Authenticated responses unique to each user (unless using very specific cache keys and encryption)
−- Authenticated responses unique to each user (unless using cache keys with auth)
+- Write-heavy APIs where invalidation cost exceeds cache benefit
−- Write-heavy APIs where cache invalidation cost exceeds cache benefit
- Data that changes every second (streaming metrics, live cursors)
−- When the response is already < 10 ms from origin (caching adds complexity without benefit)
## Core concepts
### Cache layers
−```
Browser Cache → CDN Edge Cache → Origin Shield → Origin Server
−```
Each layer reduces latency and origin load. A cache hit at the edge means the origin never sees the request.
−### Cache-Control header
+### Cache-Control header (operational)
−The single most important header for caching. It tells every cache layer how to handle the response.
+The single most important header for caching. Example useful for public APIs:
−```
+Cache-Control: public, s-maxage=300, stale-while-revalidate=600
−Cache-Control: public, max-age=3600, s-maxage=86400, stale-while-revalidate=43200
−```
+Notes:
+- s-maxage controls CDN freshness (overrides max-age for shared caches)
+- stale-while-revalidate lets the edge serve an expired object while fetching fresh content in the background
−| Directive | Scope | Meaning |
+- Use immutable + content-hash names for static build artifacts
−|--------------------------|-----------|------------------------------------------------|
−| \`public\` | All | Response can be cached by any cache |
−| \`private\` | Browser | Only the user's browser may cache this |
−| \`max-age=N\` | Browser | Browser considers fresh for N seconds |
−| \`s-maxage=N\` | CDN | CDN considers fresh for N seconds |
−| \`stale-while-revalidate=N\` | CDN/SW | Serve stale while fetching fresh in background |
−| \`no-cache\` | All | Must revalidate with origin before serving |
−| \`no-store\` | All | Never cache; always fetch from origin |
−| \`immutable\` | All | Content will never change (hashed filenames) |
−### Stale-while-revalidate (SWR)
+### Stale-While-Revalidate (SWR)
−The most impactful caching pattern for web apps. Users see cached content instantly while the CDN fetches a fresh copy in the background.
+SWR gives instant responses while refreshing in the background. Use SWR for public data where slightly stale results are acceptable for short windows.
−
−```
−First request: [Origin responds in 200ms] → cached at edge
−Second request: [Edge serves in 5ms] ← stale cache
−Background: [Edge revalidates with origin] → fresh cache
−Third request: [Edge serves fresh in 5ms]
−```
### Cache keys and variants
−A cache key determines what makes two requests "the same" for caching purposes. Default: URL. Custom keys can include headers, cookies, or query parameters.
+Cache keys define equivalence of requests. Default: URL. Consider adding headers (Accept, User-Agent), cookies (sparingly), or normalized query strings for controlled variants.
−## Workflow
+## Cloudflare-specific details (practical)
+- Cache-Tag header: Cloudflare supports tagging cached objects via a Cache-Tag response header. Cloudflare indexes these tags so you can purge by tag; however, Cloudflare removes the Cache-Tag header before the response reaches the end user or a Worker. See: Purge cache by cache-tags: https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-tags/.
+ - Aggregate Cache-Tag header limit: ~16 KB (about 1,000 unique tags); API calls have limits (max tag length 1,024 chars for purge calls).
−### Step 1 — Set cache headers in Next.js
+ - A single response may send multiple Cache-Tag headers; whitespace and repeated commas are normalized.
+- Purge API and limits (operational): Cloudflare offers purge-by-URL, tag, hostname, prefix, and purge-everything. Rate-limits vary by plan (examples from the docs):
+ - Purge-by-hostname/tag/prefix/everything: Free = 5 requests/min (bucket 25), Pro = 5 req/s (bucket 25), Business = 10 req/s (bucket 50), Enterprise = 50 req/s (bucket 500)
+ - Single-file purge throughput: Free ~800 URLs/s, Pro/Business ~1500 URLs/s, Enterprise ~3000 URLs/s (account-based moving average)
−```typescript
+ - Cloudflare uses token-bucket rate limiting — design your invalidation flows (bulk purges) to respect these limits: https://developers.cloudflare.com/cache/how-to/purge-cache/.
−// app/api/products/route.ts
−import { NextResponse } from "next/server";
−export async function GET() {
+- Purge result: Purged items are forced to MISS on subsequent requests (CF-Cache-Status: MISS); with Tiered Cache enabled, lower-tier revalidation may result in EXPIRED while upper-tier is revalidated.
− const products = await fetchProducts();
− return NextResponse.json(products, {
+- Important: responses that set Set-Cookie will typically not be cached by CDNs. Avoid coupling cookie-setting with cacheable payloads.
− headers: {
− "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600",
− },
− });
−}