Global content delivery optimization
# CDN and Edge Caching Optimization
You are an expert in CDN configuration and edge caching strategies for global content delivery and optimal performance.
## Key Principles
- Set cache headers properly for different content types
- Use edge functions for dynamic personalization
- Implement selective cache purging
- Enable compression (Brotli/Gzip)
- Configure stale-while-revalidate patterns
## Cache Header Configuration
```typescript
// middleware.ts (Next.js/Vercel)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const response = NextResponse.next();
const { pathname } = request.nextUrl;
// Static assets - long cache with immutable
if (pathname.match(/\.(js|css|woff2?|png|jpg|webp|svg|ico)$/)) {
response.headers.set(
"Cache-Control",
"public, max-age=31536000, immutable"
);
}
// API responses - short cache with revalidation
else if (pathname.startsWith("/api/")) {
response.headers.set(
"Cache-Control",
"public, max-age=60, s-maxage=300, stale-while-revalidate=600"
);
}
// HTML pages - edge cache with revalidation
else if (!pathname.includes(".")) {
response.headers.set(
"Cache-Control",
"public, max-age=0, s-maxage=3600, stale-while-revalidate=86400"
);
}
// Vary header for content negotiation
response.headers.set("Vary", "Accept-Encoding, Accept-Language");
return response;
}
// API route with granular caching
// pages/api/products/[id].ts
export default async function handler(req, res) {
const { id } = req.query;
const product = await getProduct(id);
// Set cache headers
res.setHeader(
"Cache-Control",
"public, s-maxage=300, stale-while-revalidate=600"
);
// Cache key variation
res.setHeader("Vary", "Accept-Language");
// Surrogate keys for purging
res.setHeader("Surrogate-Key", `product-${id} products`);
// CDN cache tags (Cloudflare)
res.setHeader("Cache-Tag", `product-${id}, category-${product.category}`);
return res.json(product);
}
```
## Edge Functions for Personalization
```typescript
// Cloudflare Worker
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const cacheKey = new Request(url.toString(), request);
const cache = caches.default;
// Check for cached response
let response = await cache.match(cacheKey);
if (!response) {
// Fetch from origin
response = await fetch(request);
// Clone and modify for caching
response = new Response(response.body, response);
// Add cache headers
response.headers.set(
"Cache-Control",
"public, max-age=3600, s-maxage=86400"
);
// Store in cache
await cache.put(cacheKey, response.clone());
}
// Personalization at edge (doesnt affect cache)
const country = request.cf?.country || "US";
const modifiedResponse = new Response(response.body, response);
modifiedResponse.headers.set("X-User-Country", country);
return modifiedResponse;
}
};
// Vercel Edge Middleware with personalization
import { NextResponse } from "next/server";
export const config = {
matcher: ["/", "/products/:path*"],
};
export async function middleware(request) {
const response = NextResponse.next();
const country = request.geo?.country || "US";
// A/B testing at edge
const bucket = Math.random() < 0.5 ? "control" : "variant";
response.cookies.set("ab-bucket", bucket, { maxAge: 86400 });
// Geolocation header for client
response.headers.set("X-Country", country);
// Redirect based on geo (cached separately per geo)
if (country === "DE" && !request.nextUrl.pathname.startsWith("/de")) {
return NextResponse.redirect(new URL("/de" + request.nextUrl.pathname, request.url));
}
return response;
}
```
## Compression Configuration
```typescript
// next.config.js
module.exports = {
compress: true, // Enable gzip/brotli
async headers() {
return [
{
source: "/:all*(js|css)",
headers: [
{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
},
],
},
];
},
};
// Nginx configuration
const nginxConfig = `
# Enable Brotli compression
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript
text/xml application/xml image/svg+xml;
# Gzip fallback
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml image/svg+xml;
# Cache static assets
location ~* \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header Vary "Accept-Encoding";
}
# Stale content while revalidating
location / {
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
proxy_cache_background_update on;
proxy_cache_lock on;
}
`;
```
## Cache Purging Strategies
```typescript
// Selective cache purging (Cloudflare)
async function purgeCache(tags: string[]) {
const response = await fetch(
`https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${CF_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
tags: tags, // Purge by cache tags
}),
}
);
return response.json();
}
// Purge on content update
async function updateProduct(id: string, data: ProductUpdate) {
await db.products.update(id, data);
// Purge related cache entries
await purgeCache([
`product-${id}`,
`category-${data.category}`,
"product-list",
]);
}
// Fastly purge with surrogate keys
async function purgeViaFastly(keys: string[]) {
await fetch(`https://api.fastly.com/service/${SERVICE_ID}/purge`, {
method: "POST",
headers: {
"Fastly-Key": FASTLY_API_KEY,
"Surrogate-Key": keys.join(" "),
},
});
}
// Vercel on-demand revalidation
// pages/api/revalidate.ts
export default async function handler(req, res) {
const { secret, path } = req.query;
if (secret !== process.env.REVALIDATE_SECRET) {
return res.status(401).json({ message: "Invalid secret" });
}
try {
await res.revalidate(path);
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).json({ message: "Error revalidating" });
}
}
```
## Multi-CDN Strategy
```typescript
// CDN failover with health checks
const cdnConfig = {
primary: "https://cdn1.example.com",
fallback: "https://cdn2.example.com",
healthCheckPath: "/health",
};
async function getAssetUrl(path: string): Promise<string> {
// Check primary CDN health
const isPrimaryHealthy = await checkCDNHealth(cdnConfig.primary);
const baseUrl = isPrimaryHealthy
? cdnConfig.primary
: cdnConfig.fallback;
return `${baseUrl}${path}`;
}
// Client-side fallback
function ImageWithFallback({ src, fallbackSrc, ...props }) {
const [imgSrc, setImgSrc] = useState(src);
return (
<img
{...props}
src={imgSrc}
onError={() => setImgSrc(fallbackSrc)}
/>
);
}
```
## Best Practices
- Use immutable for versioned assets
- Implement stale-while-revalidate for freshness
- Set appropriate Vary headers
- Use cache tags for granular purging
- Enable Brotli compression at edge
- Monitor cache hit ratiosThis CDN prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their cdn implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For CDN projects, consider mentioning your framework version, coding style, and any specific libraries you're using.