Table of Contents
The Challenge
Cloudflare Workers Durable Objects helped us scale our API infrastructure to handle over 139 million monthly requests — while drastically reducing KV storage costs and improving response speed. In this post, we’ll walk you through exactly how we transitioned from KV and Cache API to Durable Objects, the mistakes we made, the numbers we tracked, and why DOs were the missing piece.
Our Laravel API (running on AWS) powers thousands of connected WordPress websites. These sites call various endpoints: for license checks, user-specific data, updates, and more.
But soon, we noticed something:
- Fake or spoofed requests were hitting us.
- Expired domains kept calling paid endpoints.
- Our AWS load was rising — unnecessarily.
We needed a pre-check firewall layer, and that’s where Cloudflare Workers came in.
Using Cloudflare Workers to Filter Bad Traffic
Cloudflare Workers let us inspect every request at the edge — before it reached AWS. We used it to:
✅ Block requests missing the X-Customer-Domain header
✅ Require a valid Authorization token
✅ Verify the domain wasn’t on our expired list
This logic alone dropped a lot of noise.
The expired domains list lives in Cloudflare KV (key-value), updated by our Laravel app every 6 hours and during domain connection/disconnection.
But we ran into problems with Cloudflare KV scaling.
Attempt 1: Cloudflare Cache API
Why We Tried Cache API
We wanted to use Cloudflare Cache API inside Workers to store a parsed list of expired domains, reduce KV reads, and scale better.
Sample Code Using Cache API:
const EXPIRED_KEY = "expired:hub_expired_domains:latest";
const EXPIRED_TTL = 600;
async function getExpiredDomains(env) {
const cache = caches.default;
const cacheKey = new Request("https://internal/expired-domains");
const cached = await cache.match(cacheKey);
if (cached) return new Set(await cached.json());
const version = await env.BLOCKLIST_KV.get(EXPIRED_KEY);
const raw = await env.BLOCKLIST_KV.get(`expired:hub_expired_domains:${version}`);
const parsed = JSON.parse(raw || "[]");
const response = new Response(JSON.stringify(parsed), {
headers: { "Cache-Control": `max-age=${EXPIRED_TTL}` }
});
ctx.waitUntil(cache.put(cacheKey, response.clone()));
return new Set(parsed);
}Why Cache API Failed
Despite expectations, Cloudflare Cache API wasn’t global. It works per Worker instance, meaning:
- Instances didn’t share cached data
- Every edge spun up its own empty cache
- We still hit KV tens of thousands of times
After just 2 hours, we had 238K hot KV reads. At 139M monthly requests, this wasn’t sustainable.
Attempt 2: Cloudflare Durable Objects
What Are Durable Objects?
Cloudflare Durable Objects are a shared stateful object with memory that can be accessed by any Worker instance. They’re ideal when:
- You need consistent data across edge locations
- You want to reduce repeated storage reads
How We Used Durable Objects in Cloudflare Workers
We registered a Durable Object named ExpiryCache. This object:
- Pulled the domain list from KV every 10 minutes
- Stored it in memory
- Allowed all Workers to call it
Sample Code to Check Expiration with Durable Object:
const id = env.EXPIRY_DO.idFromName("cache");
const obj = env.EXPIRY_DO.get(id);
const res = await obj.fetch(`https://internal/is-expired?id=${domain}`);
const { expired } = await res.json();Why Durable Objects Worked
✅ Shared memory across instances
✅ Zero repeated parsing or JSON overhead
✅ KV reads dropped to a handful per day
✅ Massive cost savings

KV vs Cache API vs Durable Objects: What We Learned
Real Numbers & Pricing Impact
- 139M monthly requests
- KV read pricing: $0.50/million
- That’s $70/month in reads only
- After Durable Objects: almost $0 in reads
Plus, performance improved. Expired domain checks went from 20–50ms (KV) to 2–3ms (DO memory).

Monitoring Cloudflare Worker + Durable Objects
Next, we plan to expose a /metrics route from our DO to:
- Show total expired domains cached
- Track last KV refresh timestamp
- Count blocked expired requests
Conclusion: Why Cloudflare Workers with Durable Objects Matter
Cloudflare Workers are a game-changer for filtering edge traffic. But as you scale, the choice of Cache API, KV, or Durable Objects becomes critical.
We learned that:
- Cloudflare KV is great for storage, not for high-frequency reads
- Cache API works only within a single instance and isn’t scalable
- Cloudflare Durable Objects offer a shared, consistent, scalable memory layer
If you’re running a high-volume API like ours — do yourself a favor and test Cloudflare Workers Durable Objects early.