Worker vs Durable Object
Two modes
Section titled “Two modes”GoMode supports both stateless Workers and stateful Durable Objects. The Go handler code is identical — only the routing differs.
Worker mode
Section titled “Worker mode”Requests go straight to WASM in the Worker isolate. CF spins up isolates as needed — each caches its own WASM instance.
Browser → CF Edge → Worker isolate → cached WASM instance (Go + Zig, single binary) → handle_zerobuf(reqPtr) → Response- Stateless — no shared state between requests
- Max concurrency — CF scales isolates horizontally
- Route:
/*
Durable Object mode
Section titled “Durable Object mode”Requests route through a Durable Object. WASM instantiates once and stays alive.
Browser → CF Edge → Worker → DO.fetch() → persistent WASM instance (stays alive) → handle_zerobuf(reqPtr) → Response- Stateful — in-memory state persists between requests
- Single instance — one DO globally, requests serialized
- Route:
/do/*
Comparison
Section titled “Comparison”Worker (/*) | Durable Object (/do/*) | |
|---|---|---|
| State | None | In-memory + durable storage |
| Concurrency | CF scales isolates | Single instance, serialized |
| WASM lifetime | Cached per isolate, may evict | Alive for DO lifetime |
| Throughput | ~3,764 req/sec | ~1,586 req/sec |
| Use case | APIs, transforms, auth | Sessions, counters, websockets |
When to use which
Section titled “When to use which”Use Worker mode for stateless request/response handlers — API endpoints, data transforms, SIMD compute, anything that doesn’t need shared state.
Use DO mode when you need state that persists between requests — user sessions, real-time counters, websocket connections, rate limiters.
You can mix both in the same worker:
// worker.ts — already set up this wayif (url.pathname.startsWith("/do/")) { // Stateful → Durable Object return durable.fetch(request);}// Stateless → direct WASMreturn handleRequest(request, url.pathname);