cloudflare
references/cache-reserve/patterns.md
.md 198 lines
Content
# 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