Using Cloudflare Workers KV for Feature Flags Without Stale Reads Breaking Deploys
Coordinating feature flags at the edge means balancing fast KV reads with eventual consistency. Use Workers KV for low-latency lookups and a Durable Object as an atomic write gate when immediate consistency matters.
31 Aug 2026, 03:41 UTC

You ship a flag to turn off a buggy checkout flow, the write succeeds in the API, and requests in Sydney still see the old value for a few seconds. That is the problem with coordinating feature flags across a globally distributed edge without a central database: you need low latency reads everywhere, but you also need a predictable way to change state and know when it is safe to rely on the new value.
The practical takeaway is that Cloudflare Workers KV gives you fast, globally replicated reads for flag lookups, and it is eventually consistent. If you need atomic updates or immediate read-your-writes for a toggle operation, pair KV with a Durable Object that owns the authoritative state for that flag and writes through to KV for fast reads.
Why KV fits flag reads and where it does not
Workers KV is a key-value store designed for Workers. Reads are served from the edge and are typically low latency. Writes are asynchronous and propagate globally with eventual consistency. That means a put can be acknowledged in one region and still be invisible in another for a short window.
For feature flags, eventual consistency is often acceptable for reads: serving a flag a couple seconds late is usually safer than adding latency to every request. The risk appears on writes. A toggle performed by an operator or a deployment script may be read back immediately from the same Worker invocation, but a subsequent request routed to a different edge node can still see the previous value.
Read-your-writes is only guaranteed within the same Worker invocation after a KV put. Do not assume a client that just performed a write will see it on the next edge request unless you use a stronger primitive.
Hybrid pattern: KV for reads, Durable Object for atomic updates
A Durable Object is a single-threaded, stateful object pinned to a location with strong consistency for its own storage. It adds per-request cost and a small latency overhead compared with a pure KV read, but it gives you atomic compare-and-set semantics.
A common hybrid is to keep the flag value in KV for fast reads and use a Durable Object as the write gate. The Worker reads from KV with a fallback default. Writes go through the Durable Object, which updates its in-memory state, persists it, and then writes to KV for fan-out. This gives you an atomic toggle path and a fast read path.
Worked example
Bind a KV namespace and a Durable Object class in wrangler.toml. Replace placeholders with your own IDs and names.
name = "flag-worker"
kv_namespaces = [{ binding = FLAGS_KV, id = YOUR_NAMESPACE_ID }]
durable_objects = { bindings = [{ name = FLAG_DO, class_name = FlagDo }] }
Minimal Worker that reads with fallback and delegates toggles to the Durable Object.
export default {
async fetch(request, env) {
const url = new URL(request.url)
if (url.pathname === '/flag') {
const key = url.searchParams.get('key') || 'new_checkout'
const value = await env.FLAGS_KV.get(key, { type: 'json' })
return Response.json({ key, value: value ?? false, source: 'kv' })
}
if (url.pathname === '/toggle' && request.method === 'POST') {
const { key } = await request.json()
const id = env.FLAG_DO.idFromName(key)
const stub = env.FLAG_DO.get(id)
const result = await stub.fetch(request)
return result
}
return new Response('ok')
}
}
export class FlagDo {
constructor(state, env) {
this.state = state
this.env = env
}
async fetch(request) {
const { key } = await request.json()
const current = (await this.state.storage.get(key)) ?? false
const next = !current
await this.state.storage.put(key, next)
await this.env.FLAGS_KV.put(key, JSON.stringify(next))
return Response.json({ key, value: next, updatedBy: 'durable-object' })
}
}
Deploy from a terminal where you have a Cloudflare API token with Workers edit permission.
wrangler deploy
Expected checks after deploy: the Worker URL responds to /flag and /toggle. Risk: KV writes from the Durable Object still propagate eventually, so a read immediately after a toggle may hit a node that has not yet received the KV put. The Durable Object itself returns the authoritative value for the write request.
Trade-off and limitation
KV-only reads are cheap and fast but can serve stale flags for up to a few seconds after a write. Durable Object writes are strongly consistent for the object and give you atomic toggles, but they add latency and incur per-request charges and region-specific limits. Excessive flag toggles through Durable Objects can increase cost.
Verification approach for human review: deploy the minimal script above, bind a KV namespace and Durable Object class, and observe the flag value change after a KV put via the dashboard Workers KV UI. The UI shows when the key appears after propagation. Compare latency with curl or wrk for a KV-only read versus a Durable Object transaction read to confirm the response time trade-off.
Choose KV-only when stale reads for a few seconds are acceptable and you want minimal cost. Use the hybrid pattern when a toggle must be atomic and you need an immediate authoritative response to the operator, accepting the added latency and cost.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.