Stateful & Async
Durable Counter
Canonical Durable Objects counter - globally consistent increment/decrement with strong consistency at the edge
A minimal reference for Durable Objects: a single Counter class with persistent storage, exposed via HTTP routes. Use this pattern when you need strongly consistent state at the edge (rate limits, sessions, coordination).
API Reference
GET /counter
Returns the current counter value.
Example Request
curl "https://your-worker.workers.dev/counter"Example Response
{ "value": 42 }POST /counter/increment
Increments the counter by 1.
curl -X POST "https://your-worker.workers.dev/counter/increment"POST /counter/reset
Resets the counter to 0.
curl -X POST "https://your-worker.workers.dev/counter/reset"Use Cases
- Learn how to define and export a Durable Object class
- Shared counters or rate limiters across all edge locations
- Starting point for session storage or real-time coordination
- Understanding
idFromName()for addressing a single global object
Limitations
- Demo uses a single global counter via
idFromName(); not sharded for high throughput - Requires a Durable Objects binding and migration
- No authentication; any client can increment or read the counter
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/durable-counter.
DependenciesNoneBindingsDurable ObjectsPlatformFetch API, Durable Objects
import type { Env } from "../types/env";import type { CounterAction, CounterValue } from "../types/counter";const COUNTER_NAME = "global";export function getCounterStub(env: Env): DurableObjectStub { const id = env.COUNTER.idFromName(COUNTER_NAME); return env.COUNTER.get(id);}export async function callCounter(env: Env, action: CounterAction): Promise<CounterValue> { const stub = getCounterStub(env); const response = await stub.fetch(`https://counter/${action}`, { method: action === "get" ? "GET" : "POST", }); if (!response.ok) { throw new Error(`Counter request failed with status ${response.status}`); } return (await response.json()) as CounterValue;}Deployment
Test the API
curl "https://your-worker.workers.dev/counter"
curl -X POST "https://your-worker.workers.dev/counter/increment"Local Development
cd apps/experiments/durable-counter
npm install
npm run devConfiguration
wrangler.json declares:
- Durable Object binding
COUNTER→ classCounter - Migration
v1registering theCounterclass
Cloudflare Features Used
- Durable Objects - strongly consistent state and storage
- Workers - HTTP routes that call into the DO stub