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: globalOutbound defaults to null, blocking arbitrary outbound fetches; network operations like git are 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/promises backed by the durable Workspace filesystem
  • Modules: Supply bare imports via the modules option at construction time; register trusted modules under the reserved ws: namespace (ws:git, ws:artifacts, or custom capabilities) via trustedModules
  • Networking: globalOutbound defaults to null; enable remote calls with allowGitNetwork or allowArtifactNetwork
  • 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-shell for WorkerShellBackend and @cloudflare/computer/backends/worker-javascript for WorkerJavaScriptBackend
  • Source files: Core implementations reside in packages/computer/src/backends/worker-shell/worker-shell.ts and packages/computer/src/backends/worker-javascript/worker-javascript.ts
  • Architecture: Both Worker backends mint Dynamic Workers via the Workers Loader binding and use WorkspaceServiceProxy to 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →