Inside the World
Execution and replay
Workflow 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.
Snapshot boundary ↑. Earlier decisions are already in the saved VM.
The body of a completed step is not rerun. Core supplies its saved result.
Both engines consume the same durable event model. They do not turn a step into an exactly-once operation, and neither gives each request its own Workers isolate.
Workflow code is not step code
| Code | Where it runs | What it should do |
|---|---|---|
| Workflow function | Inside the workflow runtime. | Make replayable decisions, await steps, hooks and sleeps. |
| Step body | Ordinary host code outside the workflow VM. | Call APIs, use bindings, process streams and perform external work. |
| World methods | Adapter code calling storage and delivery resources. | Implement the persistence and transport contract core expects. |
Core substitutes recorded outcomes when replay reaches completed steps. That avoids repeating the body just to rebuild decisions. A new attempt without a durable outcome can still run the body again.
QuickJS is our default
QuickJS runs in WebAssembly with its own VM heap. Core can capture that heap at an eligible suspension after enough events have been processed. The default threshold is 1,000 events; this is not a synchronous snapshot on every thousandth write.
A later delivery restores a compatible snapshot and consumes the event tail. The log remains the source of truth if no usable snapshot exists. Saved snapshots need encryption unless the deployment explicitly permits unencrypted ones.
The snapshot codec caps plaintext capture at 32 MiB. Snapshot eligibility and compatibility still depend on SDK policy, encryption and the workflow build.
The native engine uses a build-time shim
Workers do not provide Node’s node:vm. Our build transforms the workflow bundle into a factory and supplies the VM API core expects. Each replay receives its own deterministic Date, Intl and crypto context; most shared intrinsics are frozen.
Error.stackTraceLimit and Error.prepareStackTrace remain writable for host libraries. Changes affect other runs and host requests in the same isolate, even across awaits. Do not change them in workflow code. Use QuickJS when code needs independent built-ins.
This is not an untrusted-code sandbox. Dynamic source requires QuickJS. The native path does not persist VM snapshots, so more history means more replay work.
What the replay numbers mean
The recorded 10k-step probe measured 185 ms for QuickJS and 3.9 seconds for native on build adff891. The metric is the event-time gap from a completed sleep to creation of the next step, not isolated VM CPU time.
The workflow first has to execute those 10k steps. A small replay gap does not mean the whole run took milliseconds. Store/runner placement, RPC time, competing load and whether a snapshot exists all change the result.
Sources and implementation
- docs/native-engine.md
- packages/world-cloudflare/src/vm.ts
- packages/world-cloudflare/src/build.ts
- Vercel: packages/core/src/runtime/vm-mode.ts
- Vercel: packages/core/src/runtime/quickjs-snapshot-codec.ts
Repository links may require access. Vercel links point to public source or published documentation. Logical API names do not establish backend internals.