How to Configure and Choose Between Container, Worker Shell, and Worker JavaScript Backends
Import WorkerShellBackend or WorkerJavaScriptBackend from @cloudflare/computer, instantiate them with a Workers Loader binding and host Durable Object context, and register them in the backends array when constructing a Workspace to execute isolated shell commands or JavaScript modules.
The @cloudflare/computer package provides two primary WorkspaceBackend implementations that run inside Cloudflare Dynamic Workers—the Container Worker Shell and Worker JavaScript backends—alongside a full Container backend for Linux workloads. Each offers distinct isolation models, runtime capabilities, and cost profiles depending on whether you need just-bash text processing, full ECMAScript execution, or native POSIX environments.
Architectural Overview
All three backends share a consistent architecture centered on the Workspace class in packages/computer/src/workspace.ts. When you configure a backend, you provide a loader (the Workers Loader binding) and a reference to the host Durable Object (ctx, workspace props). On connect(), the backend mints a Dynamic Worker via env.LOADER.get(...) and establishes a loopback proxy using WorkspaceServiceProxy to route filesystem, git, and asset operations back to the host DO’s SQLite store.
Both Worker backends declare BackendHandle.sync = "none" because the host Durable Object’s SQLite store serves as the single source of truth, making Workspace.push() and pull() no-ops.
Backend 1: Container Worker Shell
The Container Worker Shell backend (packages/computer/src/backends/worker-shell/worker-shell.ts) provides a lightweight, just-bash interpreter for textual tooling without container startup overhead.
Runtime Characteristics
- Execution Model: Runs commands via the just-bash interpreter with a curated set of utilities (
cat,grep,awk,sed,jq,sort, etc.) - Networking:
globalOutbounddefaults tonull, blocking arbitrary outbound fetches; network operations likegitare forwarded to the host through the loopback proxy - Isolation: Executes in a fresh Dynamic Worker with no container initialization delay
- Cost: Scales cheaply with no per-session container cost
Configuration
Import from @cloudflare/computer/backends/worker-shell and instantiate with the required bindings:
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
const shellBackend = new WorkerShellBackend({
loader: env.LOADER, // Workers Loader binding
workspace: {
binding: env.WORKSPACE,
id: ctx.id
},
ctx, // DurableObjectState
// Optional: add extra just-bash command groups
commands: additionalCommands,
});
Backend 2: Worker JavaScript
The Worker JavaScript backend (packages/computer/src/backends/worker-javascript/worker-javascript.ts) executes fresh ECMAScript modules in a Dynamic Worker with Node-compatible fs APIs and capability-based integrations.
Runtime Characteristics
- Execution Model: Loads an ES module in a fresh Dynamic Worker; supports
node:fs/promisesbacked by the durable Workspace filesystem - Modules: Supply bare imports via the
modulesoption at construction time; register trusted modules under the reservedws:namespace (ws:git,ws:artifacts, or custom capabilities) viatrustedModules - Networking:
globalOutbounddefaults tonull; enable remote calls withallowGitNetworkorallowArtifactNetwork - Limits: Enforces quotas for timeouts, byte limits, concurrent execution caps, and retention windows
Configuration
Import from @cloudflare/computer/backends/worker-javascript and configure module bundles and network permissions:
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";
const jsBackend = new WorkerJavaScriptBackend({
loader: env.LOADER,
workspace: { binding: env.WORKSPACE, id: ctx.id },
ctx,
// Pre-bundle modules your ES code will import
modules: {
"math-kit": `export const double = v => v * 2;`,
},
// Enable host-side git/network forwarding
allowGitNetwork: true,
allowArtifactNetwork: false,
});
Backend 3: Container (Full Linux)
When you need native binaries, a full POSIX environment, or commands like npm install, use the Container backend (@cloudflare/computer/backends/container). Unlike the Worker backends, this spins up an actual Linux userland with complete filesystem isolation, incurring higher per-session costs and startup latency.
Configuring a Workspace with Multiple Backends
Register multiple backends by adding them to the backends array when constructing your Workspace. Select which backend to use via the backend option in workspace.exec() or workspace.runtime.exec():
import { Workspace } from "@cloudflare/computer";
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";
const workspace = new Workspace({
storage: ctx.storage,
backends: [
// Shell backend (id defaults to "worker-shell")
new WorkerShellBackend({
loader: env.LOADER,
workspace: { binding: env.WORKSPACE, id: ctx.id },
ctx,
}),
// JavaScript backend (id defaults to "worker-javascript")
new WorkerJavaScriptBackend({
loader: env.LOADER,
workspace: { binding: env.WORKSPACE, id: ctx.id },
ctx,
modules: { "utils": `export const log = console.log;` },
}),
],
});
// Execute shell commands
await workspace.exec(`
echo "Files:" && ls -R .
`, { backend: "worker-shell" });
// Execute JavaScript module
const handle = await workspace.runtime.exec(
`
import { double } from "math-kit";
import fs from "node:fs/promises";
export default async function main(input) {
const result = double(input.value);
await fs.writeFile("/workspace/result.txt", String(result));
return { result };
}
`,
{
backend: "worker-javascript",
input: { value: 21 },
encoding: "utf8",
},
);
const { result } = await handle.result(); // => { result: 42 }
Decision Matrix: When to Choose Which Backend
| Requirement | Choose | Reason |
|---|---|---|
| Textual shell tooling (grep, awk, sed) with instant scale and low cost | Container Worker Shell | No container overhead; just-bash runs directly against the host DO’s SQLite store via the loopback proxy |
Custom JavaScript modules, fs API usage, or trusted capabilities (ws:git, ws:artifacts) |
Worker JavaScript | Full ES module environment with Node-compatible filesystem and fine-grained capability control |
Native binaries, full POSIX, npm install, or complex build tools |
Container | Real Linux userland with complete tool availability |
| Isolation without containers but need custom JS and host-forwarded git | Worker JavaScript | JS execution with allowGitNetwork enabled routes git operations through the host Durable Object |
Summary
- Import paths: Use
@cloudflare/computer/backends/worker-shellforWorkerShellBackendand@cloudflare/computer/backends/worker-javascriptforWorkerJavaScriptBackend - Source files: Core implementations reside in
packages/computer/src/backends/worker-shell/worker-shell.tsandpackages/computer/src/backends/worker-javascript/worker-javascript.ts - Architecture: Both Worker backends mint Dynamic Workers via the Workers Loader binding and use
WorkspaceServiceProxyto maintain a loopback connection to the host Durable Object’s SQLite store - Sync model: Both declare
sync = "none"because the host store is the single source of truth - Selection: Choose Worker Shell for lightweight text processing, Worker JavaScript for ES module execution with custom code, and Container for full Linux environments
Frequently Asked Questions
How do I enable git operations in the Worker JavaScript backend?
Set allowGitNetwork: true in the WorkerJavaScriptBackend constructor options. This routes git commands through the host Durable Object via the loopback proxy rather than attempting direct outbound connections from the Dynamic Worker, which are blocked by default when globalOutbound is null.
Can I use npm packages with the Worker JavaScript backend?
No. The Worker JavaScript backend runs in a Dynamic Worker with only the modules you pre-bundle via the modules option and trusted modules under ws: namespaces. If you need npm install or Node.js binary execution, use the Container backend (@cloudflare/computer/backends/container) which provides a full Linux userland.
What is the performance difference between Worker Shell and Worker JavaScript?
Both backends boot instantly via Dynamic Workers with no container cold start. Worker Shell has lower memory overhead and is optimized for text stream processing via just-bash. Worker JavaScript incurs slightly higher overhead for module instantiation but provides Turing-complete execution and access to the Node.js fs APIs backed by SQLite.
How does the loopback proxy handle filesystem operations?
The backend constructs a WorkspaceServiceProxy stub that survives RPC hops between the Dynamic Worker and host Durable Object. When code in the Worker backend calls fs.readFile or git operations, the proxy serializes these requests back to the host DO, which performs the actual I/O against its SQLite store and returns results via Workers RPC.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →