Skip to content

Evaluate adopting dynamic-worker engine for host-cloudflare (Worker Loaders now open beta) #12

Description

@amondnet

Summary

Cloudflare Worker Loaders (Dynamic Workers) moved to open beta on
2026-03-24
, available to all paid Workers users. apps/host-cloudflare
currently runs the interim QuickJS-WASM substrate specifically because Worker
Loaders was in closed beta. That constraint is now lifted, so we can evaluate
switching host-cloudflare's engine seam from QuickJS to the
dynamic-worker executor (the same one apps/cloud uses), and the stale
"closed beta" comments/docs should be updated regardless.

Background

The code documents QuickJS as a temporary accommodation, not a preference:

// apps/host-cloudflare/src/execution.ts:21-26
// QuickJS-wasm is the default code substrate because it runs in a single Worker
// with no extra binding. When Cloudflare's dynamic Worker Loader leaves closed
// beta, swap CodeExecutorProvider for the dynamic-worker executor (cloud's) —
// it's a one-Layer change behind this same seam.

host-cloudflare/README.md:87-89 and notes/research/product-model.md:89
echo the same: dynamic-worker is the intended cloud runtime.

Latest status (now open beta):

What switching would gain (capability, not just speed)

QuickJS has hard limitations the dynamic-worker runtime does not:

  • Binary values: QuickJS cannot represent Blob/File/Uint8Array at the
    tool boundary at all; dynamic-worker passes them via structured clone + a
    tagged-ArrayBuffer codec.
  • Serialization fidelity: QuickJS forces JSON round-trips, losing Date /
    Map / Set; dynamic-worker uses Workers RPC structured clone.
  • Node APIs / network: QuickJS blocks fetch and has no nodejs_compat
    inside the WASM context; dynamic-worker has nodejs_compat and configurable
    globalOutbound.
  • Isolation: separate workerd isolate vs WASM memory space inside the same
    isolate.

Performance is workload-dependent and unmeasured in this repo (the "100x"
figure is isolates-vs-containers, not vs QuickJS). Isolate boot is a few ms, and
warm-cache reuse via get(id) can remove most of the per-call cost (tracked
separately as the warm-cache key fix).

Scope

  • Swap CloudflareCodeExecutorProvider in
    apps/host-cloudflare/src/execution.ts from makeQuickJsExecutor() to
    makeDynamicWorkerExecutor({ loader: env.LOADER }) behind the existing
    CodeExecutor seam (the "one-Layer change" the comment describes).
  • Add the worker_loaders binding (LOADER) to
    apps/host-cloudflare/wrangler.jsonc.
  • Confirm the deployment's Workers plan is paid (open-beta requirement).
  • Decide whether QuickJS stays as a fallback or is removed for host-cloudflare.
  • Update the stale "closed beta" comments and README.md seam table
    (the README already lags reality on R2 blobs + the MCP-session Durable
    Object — refresh those while here).
  • e2e coverage proving code execution + binary/tool I/O works on the new
    runtime; gate with format:check / lint / typecheck / test.

Relationship to other work

  • Depends on / benefits from the warm-cache get(id) key fix in
    runtime-dynamic-worker (separate issue) for latency.
  • Independent of the github_app auth work (separate issue).

Decision needed

Whether to actually adopt dynamic-worker for host-cloudflare now, or only
update the stale docs/comments and keep QuickJS until a benchmark justifies the
switch. This issue tracks the evaluation; the doc/comment refresh is worth doing
either way.


Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions