I’ve used cloud functions of many flavors over the years, from AWS Lambda to Google Cloud Functions to Val Town. Cloudflare Workers is the latest and greatest, a great refinement of the genre, and it’s the canvas for most of my programming these days.
So here’s a Cloudflare Workers thing.
Workers grant you programmatic access to Cloudflare’s caching infrastructure, so it seems like you ought to be able to run a tight little globally-cached web server, merrily spitting out files stored in R2, like so:
export default { async fetch(request, env, ctx) { const cache = caches.default; const cachedResponse = await cache.match(request); if (cachedResponse) { return cachedResponse; } // Not in the cache, so, proceed to R2 const url = new URL(request.url); const key = url.pathname.slice(1); // to make R2 key const object = await env.BUCKET.get(key); if (object === null) { // return 404 page } const freshResponse = new Response(object.body, { status: 200, headers: { "Content-Type": object.httpMetadata.contentType || "text/html", "Cache-Control": "public, max-age=604800", "Festina-Lente": "true" }, }); // Cache it!! ctx.waitUntil(cache.put(request, freshResponse.clone())); return freshResponse; }, };Seems like it … but, alas, it’s not that simple, for two reasons:
- The cache available to Workers is per-datacenter, rather than global like Cloudflare’s “traditional” cache. This means that the first request to any given datacenter won’t be cached, which is annoying, but not a showstopper.
Here is the showstopper:
- The cache available to Workers can't be controlled by the Cache API. So, to purge files from the Workers cache (after, e.g., uploading fresh versions to R2), you'd have to write your own invalidation layer.
Which maybe sounds fun to some people — freaks! — but, for me, the attraction here was simplicity.
Here I will be precise. There is one way to control the Workers cache using the Cache API. You can simply
{ purge_everything: true }but that feels pretty gross, right? Again, the attraction here was something light and elegant, and PURGING EVERYTHING whenever you change a comma in a blog post is not elegant.
But Robin (you might say, as I said to myself), why don’t you just use a worker as a traditional “origin”, running its responses through the same caching logic that Cloudflare applies to any other origin, e.g. the old Linux box whirring next to your minifridge? Another disappointment. When you connect a domain to a worker, Cloudflare passes requests straight through, as Chris Krycho discovered.
For anyone else struggling with this — maybe you found this post via search — here is my main clarifying takeaway: the Workers Cache API should be considered a totally separate system from the Cache API and indeed the global, “traditional” Cloudflare cache. It is not, in fact, totally separate, but that assumption sets you on the right track. It did for me, at least.
P.S. The circuitous complexity of this page in Cloudflare’s docs might illustrate the depth of the confusion here 😵💫
P.P.S. Type it this many times in a row, and you realize “worker” is a weird-looking, weird-sounding word. Wrrr-krrr?!
To the blog home page.png)

