Cache Reserve
By the end of this lesson you will understand what cache eviction is, why it forces your origin to serve more traffic than expected, how Cache Reserve eliminates this using R2, and when it is worth enabling on your zone.
Cache Reserve is available on the Paid plans only (Pro, Business, Enterprise). It is billed based on the volume of data stored in R2 and the number of Class A and Class B R2 operations. There is no free tier for Cache Reserve itself.
This lesson explains how it works and when to consider it, since understanding the problem it solves is valuable even on the free plan.
The Problem: Cache Eviction
Cloudflare's edge caches are in-memory — fast, but finite in size. When a PoP's cache fills up, it must discard (evict) older or less-popular entries to make room for new content. This is called cache eviction.
Your e-commerce site has 80,000 product images. Your top 100 products get thousands of views per day — they stay in cache. But the other 79,900 products might receive only 1–5 views per week each. At that frequency, their images are evicted from every PoP between requests. Every view is a cache MISS — and a direct call back to your origin.
This is the long-tail eviction problem: content that is valid (not expired) but infrequent keeps getting thrown out of the in-memory cache and generates unnecessary origin load.
flowchart TD
subgraph NoCR["Without Cache Reserve"]
A_USER["User requests\nrare product image"] --> A_POP["Edge PoP"]
A_POP -->|"Not in memory\n(evicted by popular content)"| A_ORIGIN["Origin Server\n⚠️ Cache MISS"]
A_ORIGIN -->|"Serve image"| A_POP
A_POP -->|"Store in memory\n(will be evicted again soon)"| A_C["In-Memory Cache\n(short-lived)"]
end
subgraph WithCR["With Cache Reserve"]
B_USER["User requests\nrare product image"] --> B_POP["Edge PoP"]
B_POP -->|"Not in memory"| B_CR["Cache Reserve\n(R2 — persistent ✅)"]
B_CR -->|"Found in R2\n(no origin call)"| B_POP
B_POP -->|"Serve image"| B_USER
end
style A_ORIGIN fill:#dc2626,color:#fff,stroke:#b91c1c
style B_CR fill:#16a34a,color:#fff,stroke:#15803d
What Is Cache Reserve?
Cache Reserve is a persistent cache layer backed by Cloudflare R2 object storage. When Cache Reserve is enabled, Cloudflare writes cacheable responses to R2. On future cache misses, the edge PoP checks R2 before going to your origin.
Think of it as the difference between RAM and a hard drive:
An in-memory CDN cache is like RAM — blazing fast, but limited and volatile. Cache Reserve is like an SSD connected to every PoP simultaneously — slightly slower than RAM, but persistent, vast, and never evicts content arbitrarily.
| Cache Layer | Backed By | Speed | Eviction | Size |
|---|---|---|---|---|
| Edge in-memory | RAM (per PoP) | Fastest | Yes — LRU eviction | Limited per PoP |
| Tiered Cache hub | RAM (hub PoP) | Fast | Yes — LRU eviction | Larger, shared |
| Cache Reserve | R2 object storage | Fast (no origin RTT) | ❌ Never | Effectively unlimited |
| Origin | Your servers | Slowest | N/A | Your responsibility |
The Full Three-Layer Hierarchy
When both Tiered Cache and Cache Reserve are enabled, Cloudflare's lookup chain becomes:
flowchart LR
USER["User Request"] --> EDGE["Edge PoP\n(Layer 1: In-Memory)"]
EDGE -->|"In-memory HIT"| USER
EDGE -->|"In-memory MISS"| HUB["Tiered Cache Hub\n(Layer 2: In-Memory Hub)"]
HUB -->|"Hub HIT"| EDGE
HUB -->|"Hub MISS"| CR["Cache Reserve\n(Layer 3: R2 Persistent)"]
CR -->|"Reserve HIT (REVALIDATED)"| HUB
CR -->|"Reserve MISS"| ORIGIN["Your Origin Server"]
ORIGIN -->|"Fresh response\n→ stored in R2 + edge"| CR
style EDGE fill:#f6821f,color:#fff,stroke:#e5711e
style HUB fill:#f59e0b,color:#fff,stroke:#d97706
style CR fill:#16a34a,color:#fff,stroke:#15803d
style ORIGIN fill:#6b7280,color:#fff,stroke:#4b5563
Lookup order:
- Edge PoP in-memory — instant HIT (fastest)
- Tiered Cache hub in-memory — fast HIT from nearby hub (if Tiered Cache enabled)
- Cache Reserve (R2) — persistent HIT, no origin call
- Origin — only reached when none of the above layers have the content
The result: your origin only receives a request for a given object once per Cache Reserve TTL — regardless of how rarely the object is requested.
How Cache Reserve Stores Content
Cache Reserve stores content in R2 using the same cache key that Cloudflare's edge cache uses. You do not need to manage the R2 bucket — Cloudflare does this automatically using a dedicated, internally managed bucket.
What Gets Stored
Cache Reserve stores responses that are:
- Eligible for cache (either by default static extension, or via a Cache Rule with "Eligible for cache")
- Successful responses (HTTP 2xx status codes)
- Within size limits (up to 512MB per object)
What Does NOT Get Stored
| Content | Why Excluded |
|---|---|
Cache-Control: private responses | Must not be shared between users |
Cache-Control: no-store responses | Explicitly opted out of all caching |
| Bypass Cache rule matches | Explicitly bypassed |
| Non-2xx responses | Errors and redirects are not persisted |
Responses with Set-Cookie (usually) | May contain user-specific state |
Cache Reserve TTL and Revalidation
Cache Reserve uses its own internal TTL separate from the Edge TTL defined in your Cache Rules:
| TTL Type | What It Controls | Default |
|---|---|---|
| Edge TTL (Cache Rule) | How long the in-memory PoP/hub holds content | Varies by plan |
| Cache Reserve TTL | How long R2 holds the object before revalidating with origin | 30 days (default) |
When the Cache Reserve TTL expires for an object, Cloudflare revalidates with your origin (using conditional requests like If-None-Match / If-Modified-Since). If the origin confirms the content is unchanged (304 Not Modified), the TTL is renewed in R2 without downloading the full object again. Your origin only serves the full body if the content actually changed.
sequenceDiagram
participant PoP as Edge PoP
participant CR as Cache Reserve (R2)
participant ORG as Origin
Note over CR: Cache Reserve TTL expires for /product/image.jpg
PoP->>CR: Fetch /product/image.jpg
CR->>ORG: GET /product/image.jpg\nIf-None-Match: "abc123"
ORG-->>CR: 304 Not Modified (content unchanged)
CR-->>PoP: Serve cached content (TTL renewed in R2)
Note over ORG: ✅ No full file transfer — just a 304 header
Pricing Model
Cache Reserve is billed via R2 pricing on the underlying object storage operations:
| Metric | Cost |
|---|---|
| Storage | ~$0.015 per GB per month |
| Class A Operations (Write to R2 on first cache MISS) | $4.50 per million operations |
| Class B Operations (Read from R2 on Cache Reserve HIT) | $0.36 per million operations |
| Egress from R2 to edge | ✅ Free (R2 → Cloudflare network is always free) |
The critical insight: reads from Cache Reserve are dramatically cheaper than origin egress. If your origin serves responses via a cloud provider (AWS, GCP, Azure), you pay egress fees for every byte sent. Cache Reserve reads from R2 at $0.36/M operations with zero egress cost — often 10× cheaper than origin bandwidth.
Cost Example
Scenario: E-commerce site, 500,000 product images, 2 million monthly views of long-tail products (those not popular enough to stay in edge memory):
| Without Cache Reserve | With Cache Reserve |
|---|---|
| 2M origin requests/month | ~1,000–5,000 origin requests/month (first-time MISS only) |
| ~4TB origin egress/month | ~0 origin egress (reads from R2) |
| $360 AWS egress cost/month | ~$0.72 R2 Class B reads + ~$0.015/GB storage |
| ~$360+/month | ~$10–15/month |
Enabling Cache Reserve
Prerequisites
- A paid Cloudflare plan (Pro, Business, or Enterprise)
- Tiered Cache should be enabled first — Cache Reserve works best positioned after Tiered Cache in the lookup chain (both features are designed to be used together)
Steps
- Go to Cloudflare Dashboard → your domain → Caching → Cache Reserve
- Toggle "Enable Cache Reserve"
- Click Save
That's all — Cloudflare automatically begins storing cacheable responses in the managed R2 bucket.
Verify with Headers
Responses served from Cache Reserve include a specific cf-cache-status value:
cf-cache-status | Meaning |
|---|---|
| HIT | Served from edge in-memory cache |
| MISS | Not in any cache; fetched from origin |
| REVALIDATED | Content found in Cache Reserve (R2), origin confirmed unchanged (304) |
| UPDATING | Stale content served while origin is being contacted for a fresh copy |
curl -sI https://example.com/product/rare-item.jpg | grep cf-cache-status
# cf-cache-status: REVALIDATED ← served from Cache Reserve ✅
When Cache Reserve Is Worth Enabling
Cache Reserve has a real cost (R2 storage + operations). Evaluate whether it makes sense for your use case:
| Scenario | Cache Reserve Useful? | Reasoning |
|---|---|---|
| Large product catalogue (50k+ SKUs) with uneven traffic | ✅ Yes | Long-tail product images evicted from in-memory cache → R2 fills the gap |
| News / media site with large archive of articles | ✅ Yes | Old articles rarely accessed but valid → Cache Reserve prevents origin calls |
| SaaS dashboard (all dynamic, personalised content) | ❌ No | Content must be bypassed / not cacheable anyway |
| Small blog (100 posts, all popular) | ❌ Not needed | Content stays in in-memory cache — eviction unlikely |
| Video streaming platform | ✅ Yes | Large video files serve from R2 with no egress costs |
| API with responses tailored per user | ❌ No | Should not be cached at all |
Cache Reserve vs Tiered Cache — Full Comparison
| Aspect | Tiered Cache | Cache Reserve |
|---|---|---|
| Problem solved | Multiple PoPs calling origin independently for the same popular content | Long-tail content being evicted from memory between requests |
| Storage medium | In-memory (volatile, finite) | R2 object storage (persistent, vast) |
| Eviction | Yes — LRU | ❌ None — R2 is persistent storage |
| Speed | Fast (memory) | Slightly slower than memory, vastly faster than origin |
| Free? | ✅ Generic topology is free | ❌ Paid (R2 storage costs) |
| Best for | High-traffic popular content | Low-traffic, long-tail content with a large asset library |
| Used together? | ✅ Yes — complementary | ✅ Yes — both should be enabled together |
Common Misconceptions
"Cache Reserve is just a bigger edge cache"
Reality: Cache Reserve is backed by R2 object storage — fundamentally different from in-memory edge caching. It provides persistence (no eviction) rather than speed. While it is faster than your origin, it is slower than in-memory edge cache for content that fits there.
"Cache Reserve makes Tiered Cache unnecessary"
Reality: They solve different problems. Tiered Cache reduces origin calls for popular content by preventing multiple PoPs from independently calling origin. Cache Reserve prevents origin calls for infrequent content that gets evicted from memory. You want both for maximum origin shielding.
"Enabling Cache Reserve will cache my private user data"
Reality: Cache Reserve never stores responses with Cache-Control: private, no-store, active session cookies, or Bypass Cache rules. Responses that should not be cached are excluded automatically. The same safety rules that protect in-memory edge caching protect Cache Reserve.
"Cache Reserve's TTL is the same as my Edge TTL"
Reality: Cache Reserve has its own 30-day default TTL, independent of the Edge TTL set in your Cache Rules. A resource with a 1-hour Edge TTL may still be in Cache Reserve for 30 days — serving subsequent edge misses without ever asking your origin.
Anti-Patterns to Avoid
| Don't Do This | Do This Instead |
|---|---|
| Enable Cache Reserve without first enabling Tiered Cache | Enable Tiered Cache first — Cache Reserve sits behind it in the lookup chain |
| Enable Cache Reserve just to cache a small site's 20 images | Only enable if you have a large or long-tail asset library where eviction is measurable |
| Assume Cache Reserve handles purging differently | Purges from the dashboard or API clear Cache Reserve automatically — no extra steps |
| Enable Cache Reserve without setting Edge TTL via Cache Rules | Set appropriate Cache Rules first so content is actually eligible for caching |
Ignore the REVALIDATED cf-cache-status | Track this header in analytics — it is proof Cache Reserve is working and saving origin calls |
Key Takeaways
- Cache Reserve solves the cache eviction problem — content evicted from in-memory edge cache is still served from persistent R2 storage instead of your origin.
- It introduces a third cache layer: Edge memory → Tiered Cache hub → Cache Reserve (R2) → Origin.
- Cache Reserve never evicts content arbitrarily — objects stay in R2 until the TTL expires or you purge them.
- Default Cache Reserve TTL is 30 days — revalidation sends a conditional request (304) rather than downloading the full content again.
- Enable Tiered Cache first — they are designed to work together as complementary layers.
- Best suited for: large product catalogues, media archives, video platforms, and any site with long-tail assets that don't stay in memory.
- Billed via R2 pricing — typically 10× cheaper than origin egress for sites on cloud infrastructure.
- Purges automatically propagate through Cache Reserve — no extra steps needed.
What's Next
- Continue to the next module: DDoS Protection to learn how Cloudflare protects your origin from volumetric attacks.