Not a primitive I'd use on its own: it's a piece of infrastructure that shines inside a bigger architecture. The pattern I recommend: the Worker is the door, the object is the room, and AWS gets the minutes when the meeting ends. During the event, the object is the source of truth. When it's over, it posts the result and the full log to AWS (Postgres for money and reporting, S3 for the data lake), retries until AWS acknowledges, then deletes its own data.
Unlimited objects per account, no region to pick upfront, each with a real SQLite database (many tables, indexes, joins, triggers). D1 is built on Durable Objects; D1 is a database, a Durable Object is a tiny server that owns one.
Use it when
- All four together: one thing with live shared state (a lot, a room, a document, a game, a device), many clients connected to it at once, a single referee (first wins, no double-booking), and a lifespan or independence (it lives for an event; you rarely query across many things).
- Live auctions and bidding.
- Flash-sale and ticket inventory holds (shard by section: about 1,000 requests a second per object).
- Collaborative editing and whiteboards (Liveblocks and tldraw run on them).
- Live polls, Q&A, chat rooms, game lobbies.
- Per-user AI agent sessions (Cloudflare's Agents SDK is built on them), global rate limiters, IoT command and acknowledgement.
Don't use it when
- Ingest-and-report workloads (telemetry, logs, analytics): Postgres wins.
- Anything that needs SQL across all objects. There's no cross-object query.
- Strict Australian data residency: there's no Australian jurisdiction, only an Oceania location hint.
- Per-tenant databases when you need daily cross-tenant reporting.
Pricing
On Workers Paid: 1M requests included, then $0.15 per million. Duration: 400,000 GB-s included, then $12.50 per million GB-s (always billed at 128 MB, not billed while hibernating). Incoming WebSocket messages count 20:1; outgoing messages are free. Rows written: 50M included, then $1 per million. Storage: 5 GB included, then $0.20/GB-month.
Gotchas, with fixes
Gotcha: Single-threaded isn't automatically transactional across an await. If you await an outside call (asking AWS whether a bidder is verified) between reading the price and writing the bid, other bids run in the gap.
Fix: Do outside checks before the critical section. Keep read → check → write → broadcast synchronous (the SQLite API is synchronous, or use transactionSync).
Gotcha: Every deploy restarts all Durable Objects and drops every WebSocket.
Fix: Clients must reconnect automatically. Don't deploy during a live event.
Gotcha: No published maximum of WebSockets per object. The real ceilings are one thread, 128 MB and about 1,000 incoming requests a second.
Fix: Up to about 2,000 watchers connect directly. Above that, fan out through helper objects that each hold 1,000 to 2,000 sockets, and batch broadcasts every 50–100 ms.
Gotcha: Alarms can fire more than once.
Fix: Make the alarm handler idempotent: check the object's state before acting.
Gotcha: An object is created near its first request (or where locationHint says) and never moves.
Fix: Pass locationHint 'oc' on first access for Australian users.
Gotcha: 10 GB per object, 100 columns per table, 2 MB per row.
Fix: Design the schema around one entity (this auction, this room), and export finished data to AWS.
Provisioning
Official Pulumi package · Official Terraform provider
Declared on the Worker: @pulumi/cloudflare WorkersScript bindings and migrations (newSqliteClasses, renamedClasses…). Individual objects aren't infrastructure: they're created on first use by name.
Instead, consider
- API Gateway API Gateway WebSocket + Lambda works, but at about $407 a month vs $15–30 for the same auction, with a 2-hour connection limit.
- Neon (serverless Postgres) The data must be queried across entities. Reconcile finished events into Postgres.
Worked examples
Where it fits
- Something live that many people watch at once: Pick 02.
The room. One referee per auction, document or room, holding every WebSocket.
- A traffic spike I can see coming: Pick 02.
Exact stock counters. Instant "you got one" or "sold out", no overselling.
- Device and IoT data: Don't.
Each object only sees its own data, so there's no SQL across devices for reports. Use them only for sending commands back to devices; the readings belong in Postgres.
Instead: Neon (serverless Postgres)
Sources
Last reviewed by Nicolas Dao