Loading blog posts...
Loading blog posts...
Loading...

Every request hitting your Workers-powered app has been executing code, even when the response hasn't changed in hours. That serverless tax just ended. Cloudflare's Workers Cache launch on July 6, 2026 flips the architecture: cache now runs before your Worker, serving cached responses without burning a single millisecond of CPU time.
Traditional edge caching treated Workers as middleware. A request comes in, the Worker runs, and the Worker decides whether to fetch from cache or origin. Even cache hits still invoked the Worker, which meant CPU billing and extra latency on every single request.
Workers Cache turns that flow on its head. A tiered caching layer now sits in front of the Worker. If a cached response exists, Cloudflare serves it straight from the edge and your Worker never runs. Zero CPU time billed.
This matters a lot for server-rendered apps. Frameworks like Astro, Next.js, Remix, SvelteKit, and TanStack Start pushed Workers from "smart proxy" into "real origin." The tradeoff was paying a "serverless rendering penalty" on every request, even when thousands of users were asking for the same page.
With Workers Cache, the render-on-demand, cache-at-edge pattern becomes financially realistic for high-traffic SSR.

The shift isn't just about speed - it's about ownership. This is your Worker's cache, not the zone's cache. Instead of juggling zone-level rules, you opt in with a simple Wrangler config:
toml[cache] enabled = true
And that's the whole switch. No more bouncing between Cache Rules, Page Rules, and file-extension lists in zone settings. Cache behavior travels with the Worker wherever it deploys: custom domains, workers.dev, service bindings, preview URLs, Workers for Platforms tenants, and named WorkerEntrypoint classes.
That enabled = true line tells Cloudflare to check cache before invoking your Worker. The actual caching behavior still comes down to the HTTP headers your Worker returns. Think of it as joining the system, then controlling it with standard cache semantics.
Cache config becomes portable and version-controlled right alongside your app code, as described in Cloudflare's configuration docs.
Cloudflare's global network spans 337 cities with 13,000+ interconnections. Workers Cache uses a two-tier structure across that network.
A lower-tier cache sits close to users. If that misses, the request checks an upper-tier aggregation cache before Cloudflare even considers running your Worker. That upper tier pools cache fills across regions, which typically drives much better hit ratios for globally distributed apps.
Here's what that looks like in practice: a user in São Paulo and a user in Singapore requesting the same resource don't both trigger Worker executions. The first request populates the upper tier, and later requests from other regions can hit that aggregated cache. You get better global cache efficiency without building regional infrastructure or managing multi-region invalidation.

A strong SSR caching setup usually comes down to TTL plus background refresh:
textCache-Control: public, max-age=300, stale-while-revalidate=3600
That header tells Cloudflare to serve cached content for 5 minutes, then keep serving stale content for up to an hour while kicking off a background refresh. Users keep getting instant responses, and your Worker typically runs once per refresh cycle, not once per user.
max-age=300 is the "fresh" window where responses serve without any revalidation. After 5 minutes, stale-while-revalidate=3600 takes over: Cloudflare returns the stale response immediately while also invoking your Worker in the background to refresh the cache.
If SSR has felt slow because of cold-cache spikes, this pattern is the fix. Cloudflare's announcement calls it out explicitly as a way to cut Worker invocations while keeping content fresh.
Purging everything is the fastest way to torch your hit rate. Workers Cache supports tag-based invalidation:
javascriptexport default { async fetch(request, env, ctx) { const response = await renderProductPage(request); return new Response(response.body, { headers: { 'Cache-Control': 'public, max-age=3600', 'Cache-Tag': 'product:123, category:electronics, homepage-featured' } }); } }
When product 123 changes, purge just that tag:
javascriptawait ctx.cache.purge({ tags: ['product:123'] });
Cache-Tag takes comma-separated values, so one response can belong to multiple invalidation groups. When ctx.cache.purge runs with a tag, Cloudflare invalidates every cached response carrying that tag across the entire network. Cloudflare says this completes in under 150ms globally, based on the instant purge announcement.
For e-commerce, CMSes, and any app with connected content, changes can invalidate exactly what needs to change, without wiping entire cache layers.

Workers Cache doesn't force an all-or-nothing approach. Config can vary between your default export, named WorkerEntrypoint classes, service binding calls, and ctx.exports loopback calls.
| Entrypoint Type | Caching Recommendation |
|---|---|
| Auth/routing gateway | Disabled |
| API aggregator | Enabled with short TTL |
| SSR renderer | Enabled with stale-while-revalidate |
| Durable Object read layer | Enabled |
| AI inference endpoint | Enabled for repeated queries |
A common pattern is a gateway Worker that handles auth (don't cache it) and routes to backend Workers that render expensive pages (cache them aggressively). Each piece gets caching that fits its role without compromising security or freshness. If your project already looks like a microservice-style Worker setup, you can tune each component independently.
Workers Cache changes billing in ways that can either save money or surprise you. Cache hits count as standard Workers requests ($0.30 per million after 10M included) but bill zero CPU time.
Warning
Previously free static asset requests and worker-to-worker service binding calls may become billable at standard request rates when Workers Cache is enabled.
Cloudflare's pricing documentation gives a concrete example: a Worker handling 100 million requests per month averaging 7ms CPU per request drops from $45.40/month to $34.20/month with an 80% cache hit rate. That's roughly a 25% total bill reduction and 84% lower CPU overage costs.
| Metric | Before Workers Cache | After (80% hit rate) |
|---|---|---|
| Total requests | 100M | 100M |
| Worker executions | 100M | 20M |
| CPU time billed | 700M ms | 140M ms |
| Monthly cost | $45.40 | $34.20 |
The savings come from CPU time, not request counts. If your current setup routes static assets through Workers "for free," turning on Workers Cache could raise costs. Teams that win big here usually have high hit rates and CPU-heavy Workers. If your Worker is light and your hit rate is low, the math can go the other way. Model your own traffic before rolling out broadly.
For AI workloads, caching tokens and embeddings can cut GPU compute charges on repeated queries. If your Worker calls an inference API, caching common prompts avoids redundant compute.
javascriptexport default { async fetch(request, env, ctx) { const prompt = await request.text; const cacheKey = `inference:${hashPrompt(prompt)}`; const response = await generateResponse(prompt, env); return new Response(JSON.stringify(response), { headers: { 'Cache-Control': 'public, max-age=86400', 'Cache-Tag': `model:${env.MODEL_VERSION}` } }); } }
hashPrompt creates a deterministic cache key from the input. When the same prompt shows up again, Workers Cache can serve the cached inference result without invoking your Worker or the downstream model. Tagging entries with the model version gives you a clean purge story whenever you ship a new model. Edge AI endpoints can serve repeated queries at CDN speeds with no inference cost.
Important
Responses containing Set-Cookie or Authorization headers are not cached by default. If your SSR framework sets session cookies on every response, you'll get zero cache hits.
The Vary header also needs real discipline. Every unique combination of varied headers creates a separate cache entry. Vary: Accept-Encoding is fine. Vary: Cookie usually blows your cache into per-user entries and defeats the point.
Don't assume savings until you've checked hit ratios in Workers Observability. A 20% hit rate on a CPU-light Worker can easily end up costing more than the old setup. The feature is powerful, but it won't fix a mismatched caching strategy on its own.
Start here (your first step)
Add [cache]\nenabled = true to your wrangler.toml on a staging Worker and watch the Observability dashboard for cache hit rates.
Quick wins (immediate impact)
Cache-Control: public, max-age=300, stale-while-revalidate=3600 headers to your heaviest SSR routesSet-Cookie headers that block cachingDeep dive (for those who want more)
Workers Cache is one of the biggest shifts in Workers economics since launch. Moving from "cache after Worker" to "cache before Worker" removes the core cost issue that made SSR expensive at scale.
If your team is running server-rendered apps on Workers, this is the feature that makes the platform cost-competitive with the classic CDN-plus-origin model, while keeping the simple deploy story and global reach that drew teams to Workers in the first place.
The worker-owned model also hints at where edge computing is going: portable, self-contained deployments that carry caching behavior with them. Zone-level configuration starts to look like legacy plumbing. Application-level control is where things are headed.