# How to Configure and Choose Between Container, Worker Shell, and Worker JavaScript Backends

> Configure and choose Container, Worker Shell, or Worker JavaScript backends for your Cloudflare Workers. Learn how to register them with Workspace for efficient execution.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: how-to-guide
- Published: 2026-08-08

---

**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`](https://github.com/cloudflare/computer/blob/main/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`](https://github.com/cloudflare/computer/blob/main/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:

```typescript
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`](https://github.com/cloudflare/computer/blob/main/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:

```typescript
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()`:

```typescript
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`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/worker-shell/worker-shell.ts) and [`packages/computer/src/backends/worker-javascript/worker-javascript.ts`](https://github.com/cloudflare/computer/blob/main/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.