Workers
A Worker is a project’s main module: its fetch handler answers the requests the runtime receives.
CellB loads a project from its wrangler configuration (wrangler.jsonc plus its main) unchanged:
loadNodeProject in Node bundles main with esbuild, as celld deploy does, and
browserProjectRuntime runs it in a browser worker. A project with assets and no main is a
static site.
{ "name": "hello", "main": "index.js", "compatibility_date": "2026-01-01" }
export default {
async fetch(request, env) {
return new Response("Hello from cells! url=" + request.url, {
status: 200,
});
},
};
This is celld’s hello example (conformance/celld-examples/hello),
copied unchanged. The conformance suite runs it on CellB in Node and in Chromium and compares the
answers with celld’s recording (conformance.md).
A Worker gets the answers celld gives
- An uncaught error answers
500,content-type: application/json, with the bodyWorker failed: rejected: <name>: <message>. A handler that returns something other than aResponseis sent as its text with status 200. - An inbound request has
request.cfset to{}. - A promise the Worker leaves rejected is the Worker’s affair. On Node, where the Worker shares the
host’s process, CellB sends it to
onUnhandledRejection(by default, one line on stderr), not to the process’sunhandledRejectionlisteners. new Response("text")carriestext/plain;charset=UTF-8, as the Fetch standard adds it; celld sends noContent-Type.- The Cache API (
caches) always misses, as on celld, which has no shared edge cache:put()consumes the response and stores nothing,match()resolves toundefined. HTMLRewriteris lol-html compiled to WASM (Miniflare’shtml-rewriter-wasm), loaded on first use.
Node and browsers give a Worker different globals
- In Node the project’s Worker shares the host’s realm and process.
process.envis the host’s, and code that writes toglobalThisaffects the whole runtime (security.md). - In a browser,
process.envholds the project’s textvarsundernodejs_compat.node:fsandnode:osload with no host behind them (existsSyncis false,os.cpus()is empty); other Node.js modules without a browser polyfill load as stubs that throw when called. - Firefox has no streaming request body. CellB gives Worker code a
request.bodythat reads the whole body first; forwarding it as another request’s body sends the text[object ReadableStream]in Firefox (gaps.md).
How it is checked
celld’s hello, webapi, router and body examples, and CellB’s worker-details,
runtime-api and node-compat projects, on Node and in Chromium.
What breaks
- Configuration CellB does not support is reported, not ignored, in
createProjectRuntime(...).unsupported: service bindings to other scripts,durable_objects.bindings[].script_name,migrations.renamed_classes,containers, compatibility flags CellB does not know. Browser tabs log it ascellb: project … shard …: unsupported: …. - Python Workers do not run: CellB runs no Pyodide.