Using Cloudflare Workers Durable Objects for Consistent State in Serverless Apps
Learn how Cloudflare Workers Durable Objects provide strong consistency and low‑latency state for serverless apps, with a concrete counter example and trade‑off discussion.
03 Feb 2026, 03:55 UTC

The problem: shared state in a stateless world
When you build a Worker that needs to keep a counter, a shared cache, or coordinate WebSocket connections, the default stateless model forces you to reach for an external store like KV or Redis. Those adds latency, extra operational overhead, and you lose strong consistency guarantees.
Why Durable Objects fit the bill
Durable Objects give you a single instance of a JavaScript class per unique key. All requests that address the same key are routed to the same V8 isolate, so method calls happen in‑process and are strongly consistent. State is written to Cloudflare’s storage automatically, surviving redeploys without a separate database.
Worked example: a simple counter
- Initialize a project:
wrangler init counter-worker(run in your terminal, requires a Cloudflare account and API token withAccount.Workers Scripts:Editpermission). - Replace the generated
src/index.jswith the following code: - Add the Durable Object binding to
wrangler.toml: - Publish:
wrangler publish(same permissions as init). - Test:
curl https://counter-worker..workers.dev/repeatedly. You should see 1, 2, 3 … increasing sequentially.
export class Counter {
constructor(state, env) {
this.state = state;
}
async increment() {
let value = await this.state.storage.get('count') || 0;
value += 1;
await this.state.storage.put('count', value);
return value;
}
}
export default {
async fetch(request, env, ctx) {
const id = env.COUNTER.idFromName('single');
const obj = env.COUNTER.get(id);
const resp = await obj.increment();
return new Response(String(resp));
}
};
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
Trade‑offs and limitations
- Bottleneck per key: Because only one instance exists for a given key, heavy traffic on the same Durable Object can become a latency hotspot. If you need true horizontal scaling for that state, consider sharding the key space (e.g., using a hash of a user ID).
- Extra network hop: Accessing a Durable Object adds a round‑trip to the object’s location, typically a few milliseconds. Pure stateless Worker code avoids this hop, so for read‑only, low‑latency paths you may still prefer KV or direct computation.
Practical verification
After publishing, open the Cloudflare dashboard → Workers → your service → Durable Objects. You’ll see the COUNTER binding and can inspect the storage usage. Redeploy the Worker with a trivial change (e.g., bump a comment) and repeat the curl test; the count should continue from where it left off, proving persistence across redeploys.
Closing
Durable Objects give you a lightweight, strongly consistent state primitive that lives alongside your Worker code. Use them when you need coordination, counters, sessions, or WebSocket hibernation, and keep an eye on per‑key load and the extra hop latency. With the steps above you can have a working counter in minutes and expand to more complex stateful patterns as your application grows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.