update skills

This commit is contained in:
2026-03-17 16:53:22 -07:00
parent 0b0783ef8e
commit f9a530667e
389 changed files with 54512 additions and 1 deletions

View File

@@ -0,0 +1,147 @@
# Cloudflare Cache Reserve
**Persistent cache storage built on R2 for long-term content retention**
## Smart Shield Integration
Cache Reserve is part of **Smart Shield**, Cloudflare's comprehensive security and performance suite:
- **Smart Shield Advanced tier**: Includes 2TB Cache Reserve storage
- **Standalone purchase**: Available separately if not using Smart Shield
- **Migration**: Existing standalone customers can migrate to Smart Shield bundles
**Decision**: Already on Smart Shield Advanced? Cache Reserve is included. Otherwise evaluate standalone purchase vs Smart Shield upgrade.
## Overview
Cache Reserve is Cloudflare's persistent, large-scale cache storage layer built on R2. It acts as the ultimate upper-tier cache, storing cacheable content for extended periods (30+ days) to maximize cache hits, reduce origin egress fees, and shield origins from repeated requests for long-tail content.
## Core Concepts
### What is Cache Reserve?
- **Persistent storage layer**: Built on R2, sits above tiered cache hierarchy
- **Long-term retention**: 30-day default retention, extended on each access
- **Automatic operation**: Works seamlessly with existing CDN, no code changes required
- **Origin shielding**: Dramatically reduces origin egress by serving cached content longer
- **Usage-based pricing**: Pay only for storage + read/write operations
### Cache Hierarchy
```
Visitor Request
Lower-Tier Cache (closest to visitor)
↓ (on miss)
Upper-Tier Cache (closest to origin)
↓ (on miss)
Cache Reserve (R2 persistent storage)
↓ (on miss)
Origin Server
```
### How It Works
1. **On cache miss**: Content fetched from origin <20><> written to Cache Reserve + edge caches simultaneously
2. **On edge eviction**: Content may be evicted from edge cache but remains in Cache Reserve
3. **On subsequent request**: If edge cache misses but Cache Reserve hits → content restored to edge caches
4. **Retention**: Assets remain in Cache Reserve for 30 days since last access (configurable via TTL)
## When to Use Cache Reserve
```
Need persistent caching?
├─ High origin egress costs → Cache Reserve ✓
├─ Long-tail content (archives, media libraries) → Cache Reserve ✓
├─ Already using Smart Shield Advanced → Included! ✓
├─ Video streaming with seeking (range requests) → ✗ Not supported
├─ Dynamic/personalized content → ✗ Use edge cache only
├─ Need per-request cache control from Workers → ✗ Use R2 directly
└─ Frequently updated content (< 10hr lifetime) → ✗ Not eligible
```
## Asset Eligibility
Cache Reserve only stores assets meeting **ALL** criteria:
- Cacheable per Cloudflare's standard rules
- Minimum 10-hour TTL (36000 seconds)
- `Content-Length` header present
- Original files only (not transformed images)
### Eligibility Checklist
Use this checklist to verify if an asset is eligible:
- [ ] Zone has Cache Reserve enabled
- [ ] Zone has Tiered Cache enabled (required)
- [ ] Asset TTL ≥ 10 hours (36,000 seconds)
- [ ] `Content-Length` header present on origin response
- [ ] No `Set-Cookie` header (or uses private directive)
- [ ] `Vary` header is NOT `*` (can be `Accept-Encoding`)
- [ ] Not an image transformation variant (original images OK)
- [ ] Not a range request (no HTTP 206 support)
- [ ] Not O2O (Orange-to-Orange) proxied request
**All boxes must be checked for Cache Reserve eligibility.**
### Not Eligible
- Assets with TTL < 10 hours
- Responses without `Content-Length` header
- Image transformation variants (original images are eligible)
- Responses with `Set-Cookie` headers
- Responses with `Vary: *` header
- Assets from R2 public buckets on same zone
- O2O (Orange-to-Orange) setup requests
- **Range requests** (video seeking, partial content downloads)
## Quick Start
```bash
# Enable via Dashboard
https://dash.cloudflare.com/caching/cache-reserve
# Click "Enable Storage Sync" or "Purchase" button
```
**Prerequisites:**
- Paid Cache Reserve plan or Smart Shield Advanced required
- Tiered Cache required for optimal performance
## Essential Commands
```bash
# Check Cache Reserve status
curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/cache/cache_reserve" \
-H "Authorization: Bearer $API_TOKEN"
# Enable Cache Reserve
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/cache/cache_reserve" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"value": "on"}'
# Check asset cache status
curl -I https://example.com/asset.jpg | grep -i cache
```
## In This Reference
| Task | Files |
|------|-------|
| Evaluate if Cache Reserve fits your use case | README.md (this file) |
| Enable Cache Reserve for your zone | README.md + [configuration.md](./configuration.md) |
| Use with Workers (understand limitations) | [api.md](./api.md) |
| Setup via SDKs or IaC (TypeScript, Python, Terraform) | [configuration.md](./configuration.md) |
| Optimize costs and debug issues | [patterns.md](./patterns.md) + [gotchas.md](./gotchas.md) |
| Understand eligibility and troubleshoot | [gotchas.md](./gotchas.md) → [patterns.md](./patterns.md) |
**Files:**
- [configuration.md](./configuration.md) - Setup, API, SDKs, and Cache Rules
- [api.md](./api.md) - Purging, monitoring, Workers integration
- [patterns.md](./patterns.md) - Best practices, cost optimization, debugging
- [gotchas.md](./gotchas.md) - Common issues, limitations, troubleshooting
## See Also
- [r2](../r2/) - Cache Reserve built on R2 storage
- [workers](../workers/) - Workers integration with Cache API

View File

@@ -0,0 +1,194 @@
# Cache Reserve API
## Workers Integration
```
┌────────────────────────────────────────────────────────────────┐
│ CRITICAL: Workers Cache API ≠ Cache Reserve │
│ │
│ • Workers caches.default / cache.put() → edge cache ONLY │
│ • Cache Reserve → zone-level setting, automatic, no per-req │
│ • You CANNOT selectively write to Cache Reserve from Workers │
│ • Cache Reserve works with standard fetch(), not cache.put() │
└────────────────────────────────────────────────────────────────┘
```
Cache Reserve is a **zone-level configuration**, not a per-request API. It works automatically when enabled for the zone:
### Standard Fetch (Recommended)
```typescript
// Cache Reserve works automatically via standard fetch
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Standard fetch uses Cache Reserve automatically
return await fetch(request);
}
};
```
### Cache API Limitations
**IMPORTANT**: `cache.put()` is **NOT compatible** with Cache Reserve or Tiered Cache.
```typescript
// ❌ WRONG: cache.put() bypasses Cache Reserve
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
response = await fetch(request);
await cache.put(request, response.clone()); // Bypasses Cache Reserve!
}
// ✅ CORRECT: Use standard fetch for Cache Reserve compatibility
return await fetch(request);
// ✅ CORRECT: Use Cache API only for custom cache namespaces
const customCache = await caches.open('my-custom-cache');
let response = await customCache.match(request);
if (!response) {
response = await fetch(request);
await customCache.put(request, response.clone()); // Custom cache OK
}
```
## Purging and Cache Management
### Purge by URL (Instant)
```typescript
// Purge specific URL from Cache Reserve immediately
const purgeCacheReserveByURL = async (
zoneId: string,
apiToken: string,
urls: string[]
) => {
const response = await fetch(
`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ files: urls })
}
);
return await response.json();
};
// Example usage
await purgeCacheReserveByURL('zone123', 'token456', [
'https://example.com/image.jpg',
'https://example.com/video.mp4'
]);
```
### Purge by Tag/Host/Prefix (Revalidation)
```typescript
// Purge by cache tag - forces revalidation, not immediate removal
await fetch(
`https://api.cloudflare.com/client/v4/zones/${zoneId}/purge_cache`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${apiToken}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ tags: ['tag1', 'tag2'] })
}
);
```
**Purge behavior:**
- **By URL**: Immediate removal from Cache Reserve + edge cache
- **By tag/host/prefix**: Revalidation only, assets remain in storage (costs continue)
### Clear All Cache Reserve Data
```typescript
// Requires Cache Reserve OFF first
await fetch(
`https://api.cloudflare.com/client/v4/zones/${zoneId}/cache/cache_reserve_clear`,
{ method: 'POST', headers: { 'Authorization': `Bearer ${apiToken}` } }
);
// Check status: GET same endpoint returns { state: "In-progress" | "Completed" }
```
**Process**: Disable Cache Reserve → Call clear endpoint → Wait up to 24hr → Re-enable
## Monitoring and Analytics
### Dashboard Analytics
Navigate to **Caching > Cache Reserve** to view:
- **Egress Savings**: Total bytes served from Cache Reserve vs origin egress cost saved
- **Requests Served**: Cache Reserve hits vs misses breakdown
- **Storage Used**: Current GB stored in Cache Reserve (billed monthly)
- **Operations**: Class A (writes) and Class B (reads) operation counts
- **Cost Tracking**: Estimated monthly costs based on current usage
### Logpush Integration
```typescript
// Logpush field: CacheReserveUsed (boolean) - filter for Cache Reserve hits
// Query Cache Reserve hits in analytics
const logpushQuery = `
SELECT
ClientRequestHost,
COUNT(*) as requests,
SUM(EdgeResponseBytes) as bytes_served,
COUNT(CASE WHEN CacheReserveUsed = true THEN 1 END) as cache_reserve_hits,
COUNT(CASE WHEN CacheReserveUsed = false THEN 1 END) as cache_reserve_misses
FROM http_requests
WHERE Timestamp >= NOW() - INTERVAL '24 hours'
GROUP BY ClientRequestHost
ORDER BY requests DESC
`;
// Filter only Cache Reserve hits
const crHitsQuery = `
SELECT ClientRequestHost, COUNT(*) as requests, SUM(EdgeResponseBytes) as bytes
FROM http_requests
WHERE CacheReserveUsed = true AND Timestamp >= NOW() - INTERVAL '7 days'
GROUP BY ClientRequestHost
ORDER BY bytes DESC
`;
```
### GraphQL Analytics
```graphql
query CacheReserveAnalytics($zoneTag: string, $since: string, $until: string) {
viewer {
zones(filter: { zoneTag: $zoneTag }) {
httpRequests1dGroups(
filter: { datetime_geq: $since, datetime_leq: $until }
limit: 1000
) {
dimensions { date }
sum {
cachedBytes
cachedRequests
bytes
requests
}
}
}
}
}
```
## Pricing
```typescript
// Storage: $0.015/GB-month | Class A (writes): $4.50/M | Class B (reads): $0.36/M
// Cache miss: 1A + 1B | Cache hit: 1B | Assets >1GB: proportionally more ops
```
## See Also
- [README](./README.md) - Overview and core concepts
- [Configuration](./configuration.md) - Setup and Cache Rules
- [Patterns](./patterns.md) - Best practices and optimization
- [Gotchas](./gotchas.md) - Common issues and troubleshooting

View File

@@ -0,0 +1,169 @@
# Cache Reserve Configuration
## Dashboard Setup
**Minimum steps to enable:**
```bash
# Navigate to dashboard
https://dash.cloudflare.com/caching/cache-reserve
# Click "Enable Storage Sync" or "Purchase" button
```
**Prerequisites:**
- Paid Cache Reserve plan or Smart Shield Advanced required
- Tiered Cache **required** for Cache Reserve to function optimally
## API Configuration
### REST API
```bash
# Enable
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/cache/cache_reserve" \
-H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application/json" \
-d '{"value": "on"}'
# Check status
curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/cache/cache_reserve" \
-H "Authorization: Bearer $API_TOKEN"
```
### TypeScript SDK
```bash
npm install cloudflare
```
```typescript
import Cloudflare from 'cloudflare';
const client = new Cloudflare({
apiToken: process.env.CLOUDFLARE_API_TOKEN,
});
// Enable Cache Reserve
await client.cache.cacheReserve.edit({
zone_id: 'abc123',
value: 'on',
});
// Get Cache Reserve status
const status = await client.cache.cacheReserve.get({
zone_id: 'abc123',
});
console.log(status.value); // 'on' or 'off'
```
### Python SDK
```bash
pip install cloudflare
```
```python
from cloudflare import Cloudflare
client = Cloudflare(api_token=os.environ.get("CLOUDFLARE_API_TOKEN"))
# Enable Cache Reserve
client.cache.cache_reserve.edit(
zone_id="abc123",
value="on"
)
# Get Cache Reserve status
status = client.cache.cache_reserve.get(zone_id="abc123")
print(status.value) # 'on' or 'off'
```
### Terraform
```hcl
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
resource "cloudflare_zone_cache_reserve" "example" {
zone_id = var.zone_id
enabled = true
}
# Tiered Cache is required for Cache Reserve
resource "cloudflare_tiered_cache" "example" {
zone_id = var.zone_id
cache_type = "smart"
}
```
### Pulumi
```typescript
import * as cloudflare from "@pulumi/cloudflare";
// Enable Cache Reserve
const cacheReserve = new cloudflare.ZoneCacheReserve("example", {
zoneId: zoneId,
enabled: true,
});
// Enable Tiered Cache (required)
const tieredCache = new cloudflare.TieredCache("example", {
zoneId: zoneId,
cacheType: "smart",
});
```
### Required API Token Permissions
- `Zone Settings Read`
- `Zone Settings Write`
- `Zone Read`
- `Zone Write`
## Cache Rules Integration
Control Cache Reserve eligibility via Cache Rules:
```typescript
// Enable for static assets
{
action: 'set_cache_settings',
action_parameters: {
cache_reserve: { eligible: true, minimum_file_ttl: 86400 },
edge_ttl: { mode: 'override_origin', default: 86400 },
cache: true
},
expression: '(http.request.uri.path matches "\\.(jpg|png|webp|pdf|zip)$")'
}
// Disable for APIs
{
action: 'set_cache_settings',
action_parameters: { cache_reserve: { eligible: false } },
expression: '(http.request.uri.path matches "^/api/")'
}
// Create via API: PUT to zones/{zone_id}/rulesets/phases/http_request_cache_settings/entrypoint
```
## Wrangler Integration
Cache Reserve works automatically with Workers deployed via Wrangler. No special wrangler.jsonc configuration needed - enable Cache Reserve via Dashboard or API for the zone.
## See Also
- [README](./README.md) - Overview and core concepts
- [API Reference](./api.md) - Purging and monitoring APIs
- [Patterns](./patterns.md) - Best practices and optimization
- [Gotchas](./gotchas.md) - Common issues and troubleshooting

View File

@@ -0,0 +1,132 @@
# Cache Reserve Gotchas
## Common Errors
### "Assets Not Being Cached in Cache Reserve"
**Cause:** Asset is not cacheable, TTL < 10 hours, Content-Length header missing, or blocking headers present (Set-Cookie, Vary: *)
**Solution:** Ensure minimum TTL of 10+ hours (`Cache-Control: public, max-age=36000`), add Content-Length header, remove Set-Cookie header, and set `Vary: Accept-Encoding` (not *)
### "Range Requests Not Working" (Video Seeking Fails)
**Cause:** Cache Reserve does **NOT** support range requests (HTTP 206 Partial Content)
**Solution:** Range requests bypass Cache Reserve entirely. For video streaming with seeking:
- Use edge cache only (shorter TTLs)
- Consider R2 with direct access for range-heavy workloads
- Accept that seekable content won't benefit from Cache Reserve persistence
### "Origin Bandwidth Higher Than Expected"
**Cause:** Cache Reserve fetches **uncompressed** content from origin, even though it serves compressed to visitors
**Solution:**
- If origin charges by bandwidth, factor in uncompressed transfer costs
- Cache Reserve compresses for visitors automatically (saves visitor bandwidth)
- Compare: origin egress savings vs higher uncompressed fetch costs
### "Cloudflare Images Not Caching with Cache Reserve"
**Cause:** Cloudflare Images with `Vary: Accept` header (format negotiation) is incompatible with Cache Reserve
**Solution:**
- Cache Reserve silently skips images with Vary for format negotiation
- Original images (non-transformed) may still be eligible
- Use Cloudflare Images variants or edge cache for transformed images
### "High Class A Operations Costs"
**Cause:** Frequent cache misses, short TTLs, or frequent revalidation
**Solution:** Increase TTL for stable content (24+ hours), enable Tiered Cache to reduce direct Cache Reserve misses, or use stale-while-revalidate
### "Purge Not Working as Expected"
**Cause:** Purge by tag only triggers revalidation but doesn't remove from Cache Reserve storage
**Solution:** Use purge by URL for immediate removal, or disable Cache Reserve then clear all data for complete removal
### "O2O (Orange-to-Orange) Assets Not Caching"
**Cause:** Orange-to-Orange (proxied zone requesting another proxied zone on Cloudflare) bypasses Cache Reserve
**Solution:**
- **What is O2O**: Zone A (proxied) → Zone B (proxied), both on Cloudflare
- **Detection**: Check `cf-cache-status` for `BYPASS` and review request path
- **Workaround**: Use R2 or direct origin access instead of O2O proxy chains
### "Cache Reserve must be OFF before clearing data"
**Cause:** Attempting to clear Cache Reserve data while it's still enabled
**Solution:** Disable Cache Reserve first, wait briefly for propagation (5s), then clear data (can take up to 24 hours)
## Limits
| Limit | Value | Notes |
|-------|-------|-------|
| Minimum TTL | 10 hours (36000 seconds) | Assets with shorter TTL not eligible |
| Default retention | 30 days (2592000 seconds) | Configurable |
| Maximum file size | Same as R2 limits | No practical limit |
| Purge/clear time | Up to 24 hours | Complete propagation time |
| Plan requirement | Paid Cache Reserve or Smart Shield | Not available on free plans |
| Content-Length header | Required | Must be present for eligibility |
| Set-Cookie header | Blocks caching | Must not be present (or use private directive) |
| Vary header | Cannot be * | Can use Vary: Accept-Encoding |
| Image transformations | Variants not eligible | Original images only |
| Range requests | NOT supported | HTTP 206 bypasses Cache Reserve |
| Compression | Fetches uncompressed | Serves compressed to visitors |
| Worker control | Zone-level only | Cannot control per-request |
| O2O requests | Bypassed | Orange-to-Orange not eligible |
## Additional Resources
- **Official Docs**: https://developers.cloudflare.com/cache/advanced-configuration/cache-reserve/
- **API Reference**: https://developers.cloudflare.com/api/resources/cache/subresources/cache_reserve/
- **Cache Rules**: https://developers.cloudflare.com/cache/how-to/cache-rules/
- **Workers Cache API**: https://developers.cloudflare.com/workers/runtime-apis/cache/
- **R2 Documentation**: https://developers.cloudflare.com/r2/
- **Smart Shield**: https://developers.cloudflare.com/smart-shield/
- **Tiered Cache**: https://developers.cloudflare.com/cache/how-to/tiered-cache/
## Troubleshooting Flowchart
Asset not caching in Cache Reserve?
```
1. Is Cache Reserve enabled for zone?
→ No: Enable via Dashboard or API
→ Yes: Continue to step 2
2. Is Tiered Cache enabled?
→ No: Enable Tiered Cache (required!)
→ Yes: Continue to step 3
3. Does asset have TTL ≥ 10 hours?
→ No: Increase via Cache Rules (edge_ttl override)
→ Yes: Continue to step 4
4. Is Content-Length header present?
→ No: Fix origin to include Content-Length
→ Yes: Continue to step 5
5. Is Set-Cookie header present?
→ Yes: Remove Set-Cookie or scope appropriately
→ No: Continue to step 6
6. Is Vary header set to *?
→ Yes: Change to specific value (e.g., Accept-Encoding)
→ No: Continue to step 7
7. Is this a range request?
→ Yes: Range requests bypass Cache Reserve (not supported)
→ No: Continue to step 8
8. Is this an O2O (Orange-to-Orange) request?
→ Yes: O2O bypasses Cache Reserve
→ No: Continue to step 9
9. Check Logpush CacheReserveUsed field
→ Filter logs to see if assets ever hit Cache Reserve
→ Verify cf-cache-status header (should be HIT after first request)
```
## See Also
- [README](./README.md) - Overview and core concepts
- [Configuration](./configuration.md) - Setup and Cache Rules
- [API Reference](./api.md) - Purging and monitoring
- [Patterns](./patterns.md) - Best practices and optimization

View File

@@ -0,0 +1,197 @@
# Cache Reserve Patterns
## Best Practices
### 1. Always Enable Tiered Cache
```typescript
// Cache Reserve is designed for use WITH Tiered Cache
const configuration = {
tieredCache: 'enabled', // Required for optimal performance
cacheReserve: 'enabled', // Works best with Tiered Cache
hierarchy: [
'Lower-Tier Cache (visitor)',
'Upper-Tier Cache (origin region)',
'Cache Reserve (persistent)',
'Origin'
]
};
```
### 2. Set Appropriate Cache-Control Headers
```typescript
// Origin response headers for Cache Reserve eligibility
const originHeaders = {
'Cache-Control': 'public, max-age=86400', // 24hr (minimum 10hr)
'Content-Length': '1024000', // Required
'Cache-Tag': 'images,product-123', // Optional: purging
'ETag': '"abc123"', // Optional: revalidation
// Avoid: 'Set-Cookie' and 'Vary: *' prevent caching
};
```
### 3. Use Cache Rules for Fine-Grained Control
```typescript
// Different TTLs for different content types
const cacheRules = [
{
description: 'Long-term cache for immutable assets',
expression: '(http.request.uri.path matches "^/static/.*\\.[a-f0-9]{8}\\.")',
action_parameters: {
cache_reserve: { eligible: true },
edge_ttl: { mode: 'override_origin', default: 2592000 }, // 30 days
cache: true
}
},
{
description: 'Moderate cache for regular images',
expression: '(http.request.uri.path matches "\\.(jpg|png|webp)$")',
action_parameters: {
cache_reserve: { eligible: true },
edge_ttl: { mode: 'override_origin', default: 86400 }, // 24 hours
cache: true
}
},
{
description: 'Exclude API from Cache Reserve',
expression: '(http.request.uri.path matches "^/api/")',
action_parameters: { cache_reserve: { eligible: false }, cache: false }
}
];
```
### 4. Making Assets Cache Reserve Eligible from Workers
**Note**: This modifies response headers to meet eligibility criteria but does NOT directly control Cache Reserve storage (which is zone-level automatic).
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const response = await fetch(request);
if (!response.ok) return response;
const headers = new Headers(response.headers);
headers.set('Cache-Control', 'public, max-age=36000'); // 10hr minimum
headers.delete('Set-Cookie'); // Blocks caching
// Ensure Content-Length present
if (!headers.has('Content-Length')) {
const blob = await response.blob();
headers.set('Content-Length', blob.size.toString());
return new Response(blob, { status: response.status, headers });
}
return new Response(response.body, { status: response.status, headers });
}
};
```
### 5. Hostname Best Practices
Use Worker's hostname for efficient caching - avoid overriding hostname unnecessarily.
## Architecture Patterns
### Multi-Tier Caching + Immutable Assets
```typescript
// Optimal: L1 (visitor) → L2 (region) → L3 (Cache Reserve) → Origin
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const isImmutable = /\.[a-f0-9]{8,}\.(js|css|jpg|png|woff2)$/.test(url.pathname);
const response = await fetch(request);
if (isImmutable) {
const headers = new Headers(response.headers);
headers.set('Cache-Control', 'public, max-age=31536000, immutable');
return new Response(response.body, { status: response.status, headers });
}
return response;
}
};
```
## Cost Optimization
### Cost Calculator
```typescript
interface CacheReserveEstimate {
avgAssetSizeGB: number;
uniqueAssets: number;
monthlyReads: number;
monthlyWrites: number;
originEgressCostPerGB: number; // e.g., AWS: $0.09/GB
}
function estimateMonthlyCost(input: CacheReserveEstimate) {
// Cache Reserve pricing
const storageCostPerGBMonth = 0.015;
const classAPerMillion = 4.50; // writes
const classBPerMillion = 0.36; // reads
// Calculate Cache Reserve costs
const totalStorageGB = input.avgAssetSizeGB * input.uniqueAssets;
const storageCost = totalStorageGB * storageCostPerGBMonth;
const writeCost = (input.monthlyWrites / 1_000_000) * classAPerMillion;
const readCost = (input.monthlyReads / 1_000_000) * classBPerMillion;
const cacheReserveCost = storageCost + writeCost + readCost;
// Calculate origin egress cost (what you'd pay without Cache Reserve)
const totalTrafficGB = (input.monthlyReads * input.avgAssetSizeGB);
const originEgressCost = totalTrafficGB * input.originEgressCostPerGB;
// Savings calculation
const savings = originEgressCost - cacheReserveCost;
const savingsPercent = ((savings / originEgressCost) * 100).toFixed(1);
return {
cacheReserveCost: `$${cacheReserveCost.toFixed(2)}`,
originEgressCost: `$${originEgressCost.toFixed(2)}`,
monthlySavings: `$${savings.toFixed(2)}`,
savingsPercent: `${savingsPercent}%`,
breakdown: {
storage: `$${storageCost.toFixed(2)}`,
writes: `$${writeCost.toFixed(2)}`,
reads: `$${readCost.toFixed(2)}`,
}
};
}
// Example: Media library
const mediaLibrary = estimateMonthlyCost({
avgAssetSizeGB: 0.005, // 5MB images
uniqueAssets: 10_000,
monthlyReads: 5_000_000,
monthlyWrites: 50_000,
originEgressCostPerGB: 0.09, // AWS S3
});
console.log(mediaLibrary);
// {
// cacheReserveCost: "$9.98",
// originEgressCost: "$25.00",
// monthlySavings: "$15.02",
// savingsPercent: "60.1%",
// breakdown: { storage: "$0.75", writes: "$0.23", reads: "$9.00" }
// }
```
### Optimization Guidelines
- **Set appropriate TTLs**: 10hr minimum, 24hr+ optimal for stable content, 30d max cautiously
- **Cache high-value stable assets**: Images, media, fonts, archives, documentation
- **Exclude frequently changing**: APIs, user-specific content, real-time data
- **Compression note**: Cache Reserve fetches uncompressed from origin, serves compressed to visitors - factor in origin egress costs
## See Also
- [README](./README.md) - Overview and core concepts
- [Configuration](./configuration.md) - Setup and Cache Rules
- [API Reference](./api.md) - Purging and monitoring
- [Gotchas](./gotchas.md) - Common issues and troubleshooting