World / Cloudflare
GitHub

Comparison

Measurements and limits

Recorded Workers results, the workload behind each number, and the failures that keep these from being unlimited-capacity claims.

Recorded probes on Workers Paid, not measurements made by this website. The latest check used build 8cddcbd and the published workflow 5.5.0 on 2026-11-14/15. Runs were unencrypted. The latest epoch had 256 store, 512 queue and 16 index shards; state and load generation requested enam. A hint does not prove colocation or residency.

Creation admissionRuns per second
Vercel limit
1,000/s
20k burst
3,574/s
50k burst
4,036/s
100k current
5,082/s
Vercel is a documented quota, not a measured baseline. Our samples used different builds and burst sizes. These bars do not compare sustained completion throughput.

Latest regression check

Typecheck and strict-unused checks passed. Unit tests passed 325, with 7 skipped. E2E passed 171, with 31 expected failures and 3 skipped. Deployed smoke and focused review found no new confirmed correctness regression.

A paired local writer benchmark did find overhead: 750 full step lifecycles averaged 144.34 ms with the old writer and 195.53 ms with the current one, about 35% more. There are five extra SQL calls per ordinary event. This isolates local writer work, not deployed end-to-end speed. Safety checks were not removed.

A large due hook-intent recovery backlog still has no measured safe burst size. No finite test here establishes universal capacity or proves every failure mode absent.

Creation is not completion

SampleRecorded resultScope of verification
100k, 8cddcbd5,082 creations/s; p50 107 ms, p95 397 ms; no creation errors.All 100,000 outputs verified in 89.1 s, about 1,123 verified/s. Server completion span was 87.6 s.
Paced 60k, 8cddcbdNominal 2,000/s; actual 1,652/s; 25 HTTP 503s.All 59,975 returned run IDs completed correctly. No output claim for calls that returned no ID.
Paced 90k, 8cddcbdNominal 3,000/s; actual 2,277/s; no creation errors.All outputs verified in 82.8 s. Short paced jobs, not an hours-long steady-load study.
100k, 4ceac874,220 creations/s; p50 93 ms, p95 237 ms; no creation errors.Historical admission sample. Every final output was not individually verified.
20k, f348a973,574/s; 19,998 accepted and completed, zero wrong outputs.Two retryable 503s during a queue-object reset.
20k rerun, f348a972,430/s; all 20,000 completed with correct output.No creation errors in this sample.
50k, f348a974,036/s; no creation errors; drained in about 3.3 minutes.No failed runs observed. Not every output independently checked.

Execution results

ProbeRecorded resultBuild
Current QuickJS fan-out30k parallel steps in 269.4 s; 35k produced executor exceededMemory.8cddcbd; higher-count probe guard temporarily raised
Current native fan-out2.5k in 28.5 s; 3k produced executor exceededMemory.8cddcbd
Byte-stream read1.75 GiB in 188.4 s, every byte correct; 2 GiB exceeded memory.8cddcbd; 16 MiB producer chunks
QuickJS fan-out1k / 5k / 10k parallel steps in 12.5 / 41.3 / 72.7 seconds.f348a97
Native fan-out1k in 6.2 seconds. Six 2k samples ranged from 20 to 32 seconds.f348a97
Spec-9 fan-out1k parallel steps in 8.5 to 10.6 seconds.f348a97
Long QuickJS run30k sequential steps, 90,003 events, 3,896 seconds.adff891
Replay gap after 10k185 ms QuickJS; 3.9 seconds native. Event timestamp gap, not VM CPU.adff891
1 GiB stream, 32 MiB chunksEvery byte correct. Reading-step throughput 14 MiB/s QuickJS, 15 MiB/s native.f348a97

In the 10k fan-out sample, 17 steps started twice. In two of six native 2k samples, larger batches restarted without an explanatory error in the captured tail. All finished correctly. The cause was not established; at-least-once delivery is visible here, not theoretical.

Limits are not all the same kind of number

QuantityVercel publishedOur measured or enforced value
Creations1,000/s.5,082/s in a 100k burst; absolute sustained maximum unknown.
Steps per run10k for Node; exempt with QuickJS snapshots enabled.30k sequential steps demonstrated, QuickJS.
Events per run25k for Node; same QuickJS exemption.90,003 demonstrated; no World-configured cap, but finite memory/throughput.
Payload50 MB.18 MiB serialized cap; 18,790,000 raw output bytes demonstrated.
Stream chunk10 MB documented.32 MiB encoded chunk cap. MB and MiB differ.
Replay240-second budget.Same SDK timeout class; 185 ms is one measured gap, not a replacement budget.

Known failure points

  • 35k QuickJS parallel steps: executor exceededMemory at 8cddcbd. A 30k run passed. The historical 20k failure is not a current fixed ceiling.
  • 3k native parallel steps: executor exceededMemory; 2.5k passed. Core replay memory grows quadratically.
  • 2 GiB in one QuickJS reading step: exceededMemory with 16 MiB producer chunks; 1.75 GiB passed.
  • Very large values: producer or consumer code can exhaust memory before a clean 413 is possible.
  • Regional distance: sequential RPC latency can dominate small steps.

Memory-failing probes stopped at the first captured event, then cancelled the run and closed streams. This proves an invocation limit, not that every retry or larger run must fail. The probe-only releases raised the example count guard to 100k, then restored it. Other gaps include outage-backlog recovery, general retained-release upgrade safety, multi-region capacity, retention and key rotation. Current platform documentation lists 128 MB per isolate, 10 GB per SQLite-backed object on Paid and 8 MB rows/values. An object’s documented 1,000 requests/s is soft, not an absolute ceiling.

Run the probes

Against your own deployed example
export WORKFLOW_BASE_URL=https://your-worker.example.workers.dev
node scripts/remote-e2e.mjs
node scripts/remote-load.mjs 1000 50 --wait --verify
node scripts/remote-bench.mjs sequentialSteps:2000
node scripts/remote-limits.mjs streamBytes:1024x32

The remote load script reports creation latency and errors. --wait --verify separately waits for completion and checks outputs. A distant single client measures its own network bottleneck too; use controlled in-region generation for a backend-admission experiment.

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