How to Set Up Caching in Cloudflare Workers - Edge Cache and Tiered Cache
Summary: Two ways to cache when a Worker calls an external API, and the three traps you will definitely hit if you don't know about them. Per-data-center cache, Tiered Cache, and cache keys.

Overview
This post is part of the Cloudflare Workers Static Site Guide - From Deployment to SEO series.
Once a Worker starts calling an external API, you soon need a cache. Without one, origin load grows in proportion to page views.
Setting it up takes a single line, but after that come a few traps you will definitely hit if you don’t know about them. In particular, the fact that the edge cache is not shared worldwide is obvious once you know it, but without that knowledge you will waste a lot of time wondering “why isn’t the cache hitting?”
What this post covers
- The two ways to cache — the
cfoption onfetch()and the Cache API - The fact that the edge cache is separate per data center, and how to deal with it
- How to reduce origin requests with Tiered Cache, and why
cache.put()doesn’t work with it - The cache key problem when the same URL returns different responses depending on headers
What it doesn’t cover
The structure and deployment of Workers Static Assets is in Cloudflare Workers Static Site Hosting - Request Flow and Billing, and local development is in How to Use wrangler - Local Development and Deployment for Cloudflare Workers.
Storage such as KV, R2, and D1 is out of scope. This post covers HTTP response caching only.
Two ways to cache
① The cf option on fetch() — hands the response over to the Cloudflare edge cache (Request documentation).
1await fetch(url, {
2 cf: { cacheTtl: 3600, cacheEverything: true },
3});
② Cache API — you put and get entries yourself.
1const cache = caches.default;
2const hit = await cache.match(key);
3if (hit) return hit;
4// ...
5ctx.waitUntil(cache.put(key, response.clone()));
Three things you need to know
The edge cache is separate per data center. Straight from the docs.
The contents of the cache do not replicate outside of the originating data center.
Tokyo doesn’t know what Seoul cached. When you serve traffic coming in from all over the world, the same URL hits the origin as many times as you have data centers.
**Tiered Cache reduces that. When a lower data center misses, it asks an upper data center** first instead of the origin. It’s free on every plan. One caveat: entries stored with cache.put() are not eligible for Tiered Cache — which is why approach ① is the better default.
The cache key is the URL. If the same URL returns different responses depending on request headers (Accept-Language and the like), leaving it as is means whoever fills the cache first serves everyone. You can change the key with cf.cacheKey, but that is Enterprise only, so on lower plans you have to put the distinguishing value in the URL query.
Summary
- If your Worker calls an external API, caching is not optional. Without it, the origin takes as many hits as you have page views.
- There are two ways to do it. Prefer
cf.cacheTtlas your default — entries stored withcache.put()can’t ride Tiered Cache. - The edge cache is separate per data center. If you serve worldwide traffic, turn on Tiered Cache. It’s free on every plan.
- If the same URL returns different responses depending on headers, you have to put the distinguishing value in the URL.
cf.cacheKeyis Enterprise only.
References
- Cache API
- Request
cfoptions —cacheTtl·cacheEverything·cacheKey - Tiered Cache
- Cloudflare Workers Static Site Hosting - Request Flow and Billing