Fix Cache-Control Headers on Cloudflare
Last updated: April 2026
Cloudflare caches based on origin Cache-Control headers and its own edge TTL. Configure both for predictable caching behaviour.
Audit your Cloudflare cache headers live โCache Rules โ recommended (2024+)
Dashboard โ Your domain โ Caching โ Cache Rules โ Create rule.
# Static assets โ cache at edge 1 year When: File extension matches js, css, woff2, png, jpg, webp Then: Edge TTL = 1 year, Browser TTL = 1 year, Cache status = Cache # API โ bypass cache When: URI path starts with /api/ Then: Cache status = Bypass
Transform Rules โ modify Cache-Control header
Dashboard โ Rules โ Transform Rules โ Modify Response Header.
# Static assets Set Cache-Control: public, max-age=31536000, immutable # API responses Set Cache-Control: no-store # HTML pages Set Cache-Control: no-cache
Cloudflare Worker โ full control
export default {
async fetch(request, env) {
const response = await fetch(request);
const url = new URL(request.url);
const headers = new Headers(response.headers);
if (url.pathname.startsWith('/api/')) {
headers.set('Cache-Control', 'no-store');
} else if (/\.(js|css|woff2|png|jpg)$/.test(url.pathname)) {
headers.set('Cache-Control', 'public, max-age=31536000, immutable');
} else {
headers.set('Cache-Control', 'no-cache');
}
return new Response(response.body, { status: response.status, headers });
}
};
stale-while-revalidate on Cloudflare
Cache-Control: public, max-age=60, stale-while-revalidate=300
Verify cache headers
curl -sI https://yoursite.com/app.js | grep -iE "cache-control|cf-cache-status|age"