Skip to content

Worker vs Durable Object

GoMode supports both stateless Workers and stateful Durable Objects. The Go handler code is identical — only the routing differs.

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: /*

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/*
Worker (/*)Durable Object (/do/*)
StateNoneIn-memory + durable storage
ConcurrencyCF scales isolatesSingle instance, serialized
WASM lifetimeCached per isolate, may evictAlive for DO lifetime
Throughput~3,764 req/sec~1,586 req/sec
Use caseAPIs, transforms, authSessions, counters, websockets

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 way
if (url.pathname.startsWith("/do/")) {
// Stateful → Durable Object
return durable.fetch(request);
}
// Stateless → direct WASM
return handleRequest(request, url.pathname);