World / Cloudflare
GitHub

Inside the World

State and delivery

How an event becomes durable work, why the outbox exists, and where transactions stop.

The event is the durable record

An accepted event changes both history and the queryable state for that run. A completed step, for example, appends its event, updates its step row and may leave dispatch work to wake the orchestrator. The relevant local changes commit together.

Conceptual transaction, not literal SQL
BEGIN;
  append event;
  apply run / step / hook / wait transition;
  record dispatch or index outbox debt;
COMMIT;

// After commit: attempt external publication.
// If interrupted: the stored debt remains retryable.

Keeping queryable rows avoids folding the entire log just to answer a status read. Keeping the log lets the SDK reconstruct the workflow’s decisions.

Why commit an outbox?

Suppose the store commits a step result and crashes before sending its wake. Without durable intent, the step is complete but the run may never hear about it. Publishing first is also unsafe: the next delivery could observe missing state.

The outbox records the obligation with the state change. After commit, publication is attempted. If acknowledgment is lost, the same intent may publish again; deduplication and replay must tolerate that.

Commit event + intent
Attempt queue publish
Mark intent delivered
Retry if still owed

Hook claims cross transaction boundaries

A forced claim must not dispose another run’s hook before validating the requester. The run store checks the real reducer in a rolled-back savepoint, then persists the accepted request and reserves its hook ID before contacting the token registry.

Validate and persist admission
Reserve token and decide ownership
Record previous owner’s disposal
Commit local event and finish intent

Operation digests and canonical decisions make retries address the same claim. A reset leaves a recoverable intent; a pending takeover prevents a third claimant from slipping between release and transfer. Disposal callbacks stay outside run gates, including when the previous owner’s start Hook has not materialized yet.

At-least-once means side effects can repeat

A queue can lose the acknowledgment after a step called an external API. It must retry because it cannot know whether the body finished. The SDK has durable step outcomes, but it cannot atomically commit your payment provider’s state with our event log.

Use a stable business idempotency key when calling external systems. A replay reading a stored result is different from retrying a step whose outcome was never durably recorded.

MechanismWhat it protectsWhat it does not promise
Queue idempotency keyRepeated admission for the same key; the first accepted payload and delay win.Exactly-once execution of a side effect.
Per-run replay serializationConcurrent orchestrator deliveries for one run.Global serialization across all runs or steps.
Pure-wake coalescingAvoids eligible replay requests already covered by a successful delivery.Dropping distinct hook inputs or arbitrary messages.
Durable in-flight stateRecovery when a shard restarts during delivery.No duplicate starts after acknowledgment loss.

Retries, limits and recovery

Counted queue attempts back off by min(attempt² seconds, 300 seconds). The World defaults to 64 attempts. Core has a separate delivery policy, whose default limit is 48. These limits are not interchangeable.

A valid positive numeric handler-error retryAfter sets a retry floor over local backoff, capped at 23 hours. A successful spec-8 timeout enqueues a fresh message before acknowledging the original, without spending its failed-delivery budget. A spec-9 zero-second continuation is a handoff rather than another counted failure. Transient depth or object-reset failures surface as retryable 503s. A fatal payload-size error is different: retrying the same bytes cannot make them fit.

Exhausted messages go to the DLQ bucket. Supported store redrives use new persisted delivery keys. Accepted deduplication keys remain stored; there is no automated retention policy to prune all historical state.

Sources and implementation

Repository links may require access. Vercel links point to public source or published documentation. Logical API names do not establish backend internals.

Browse topics or type to search

IntroductionA Workflow SDK v5 World built on Cloudflare Workers, Durable Objects and R2. Here is what runs where, why each part exists, and what the measurements actually show.Same SDK, different infrastructureA workflow is a log you can replay.Three jobs, kept separateA workflow is a log you can replay.Recorded results, not promisesA workflow is a log you can replay.Read the system in orderA workflow is a log you can replay.The architectureAn ordered store for each run, delivery capacity shared across shards, and execution kept off the queue objects.Where everything livesThe architectureOrder state, distribute executionThe architectureRouting without a global directoryThe architectureWhat the design buys, and costsThe architectureLife of a requestFollow the ordinary static-workflow start path, then the deliveries that turn the stored intent into completed work.Our World: accepting the runLife of a requestOur World: delivering and runningLife of a requestVercel: the corresponding pathLife of a requestWhat a response does and does not guaranteeLife of a requestEvery service, explainedWhat each component owns, why it exists, how it helps, and the limit it introduces. These are logical roles, not twelve separate deployed services.Router Worker and World clientEvery service, explainedRun-store shardsEvery service, explainedQueue shardsEvery service, explainedWorkflow runners and step runnersEvery service, explainedConsumer and retained executor WorkersEvery service, explainedIndex shardsEvery service, explainedHook token registriesEvery service, explainedRun streams and VM snapshotsEvery service, explainedR2 payloads and dead lettersEvery service, explainedAlarms and cron recoveryEvery service, explainedState and deliveryHow an event becomes durable work, why the outbox exists, and where transactions stop.The event is the durable recordState and deliveryWhy commit an outbox?State and deliveryHook claims cross transaction boundariesState and deliveryAt-least-once means side effects can repeatState and deliveryRetries, limits and recoveryState and deliveryExecution and replayWorkflow decisions execute inside a deterministic runtime. Step bodies do the I/O outside it. QuickJS and the native engine trade replay work for memory and compatibility.Workflow code is not step codeExecution and replayQuickJS is our defaultExecution and replayThe native engine uses a build-time shimExecution and replayWhat the replay numbers meanExecution and replayShards and placementSpread independent runs, preserve old routing, and keep state near execution where possible. More shards are capacity, not free speed.Time picks the epoch, hash picks the shardShards and placementA location hint is a hintShards and placementWhy creation throughput is highShards and placementMany runs scale better than one enormous runShards and placementPayloads and byte streamsUse values for control data and byte streams for bulk data. Offloading to R2 removes storage-message pressure, not every memory limit.A value still has to fit in memoryPayloads and byte streamsPass a handle, then move bytes incrementallyPayloads and byte streamsThe producer must outlive the step resultPayloads and byte streamsThe current multi-GiB reader problemPayloads and byte streamsCompared with VercelTwo implementations of the same World contract. We can inspect Vercel’s public adapter, not the internals behind its managed APIs.The services Vercel’s public client usesCompared with VercelThe same jobs, different ownersCompared with VercelHow their transport worksCompared with VercelWhere our design helpsCompared with VercelRead the Vercel limits with their runtime contextCompared with VercelMeasurements and limitsRecorded Workers results, the workload behind each number, and the failures that keep these from being unlimited-capacity claims.Latest regression checkMeasurements and limitsCreation is not completionMeasurements and limitsExecution resultsMeasurements and limitsLimits are not all the same kind of numberMeasurements and limitsKnown failure pointsMeasurements and limitsRun the probesMeasurements and limitsIdentity and deploymentsBindings authorize internal access. Your application protects public routes. Encryption and retained release routing solve separate problems.Internal calls use capabilitiesIdentity and deploymentsEncryption has a narrower scope than “all data”Identity and deploymentsKeep the code that owns old historyIdentity and deploymentsHow Vercel’s identity differsIdentity and deploymentsBuild, deploy and operateThe repository root is an example application. The reusable World lives in packages/world-cloudflare. Deploy the minimal mode first, then add retained executors if you need them.Start with the exampleBuild, deploy and operateKnow which config changes affect old runsBuild, deploy and operateDeploy state first, then the retained executorBuild, deploy and operateTest the adapter, the SDK and the deploymentBuild, deploy and operateOperational work still leftBuild, deploy and operate
Local search. Nothing sent to a server.Esc to close
Documentation