CloudflareContainerBackend vs WorkerShellBackend vs WorkerJavaScriptBackend: Key Differences in the Computer SDK

The Cloudflare Computer SDK provides three distinct execution backends—Container, Worker-Shell, and Worker-JavaScript—that differ in runtime environment, filesystem handling, startup cost, and capabilities.

The Container backend spins up a full Linux container, while Worker-Shell runs a bash interpreter inside a Dynamic Worker, and Worker-JavaScript executes JS modules directly in the Worker isolate. Each backend is optimized for different workloads, from heavy native builds to fast text processing to structured JavaScript execution.

Runtime Environment Comparison

The fundamental distinction between these three backends lies in where and how your code executes.

Container Backend: Full Linux Container

The ContainerBackend creates a real Linux container that runs the computerd daemon. This provides a complete POSIX userland including bash, coreutils, arbitrary binaries, and network access.

In packages/computer/src/backends/container/index.ts, the backend wires the container daemon and defines a BackendHandle with sync: "remote"【📄】. This means the container maintains its own filesystem that must be synchronized with the host Durable Object.

Worker-Shell Backend: Bash in a Dynamic Worker

The WorkerShellBackend executes a just-bash interpreter inside a Cloudflare Dynamic Worker. No container is started. Instead, the shell forwards every filesystem call back to the host Durable Object.

According to the source code in packages/computer/src/backends/worker-shell/entrypoint.ts, this backend creates a Dynamic Worker running just-bash, registers built-in git and assets commands, and sets sync: "none"【📄】.

Worker-JavaScript Backend: Native JS Execution

The WorkerJavaScriptBackend runs JavaScript modules directly inside the Worker isolate. Unlike the shell backend, code is evaluated as a JavaScript module rather than a shell script, giving you a native-JS execution environment.

The implementation in packages/computer/src/backends/worker-javascript/module-graph.ts builds the module graph for JavaScript execution, marks the backend as callable, and also uses sync: "none"【📄】.

Filesystem and Sync Models

Backend Filesystem Handling Sync Mode
ContainerBackend Separate FUSE-backed SQLite VFS inside the container; remote push/pull to host DO "remote"
WorkerShellBackend All operations proxied to host DO's SQLite store; single authoritative source "none"
WorkerJavaScriptBackend File I/O proxied to host DO's SQLite store; same storage shape as shell backend "none"

The Container backend's remote sync mode requires explicit push/pull cycles to synchronize the container's VFS with the host Durable Object. Both Worker backends eliminate this overhead by treating the host DO as the sole source of truth.

Startup Cost and Scaling Characteristics

ContainerBackend incurs significant per-session overhead:

  • Container creation takes seconds
  • Per-session container charges apply
  • Best for long-running or compute-intensive tasks

WorkerShellBackend offers instant, cheap scaling:

  • Dynamic Worker cached per workspace (workspace-shell:${workspace.id})
  • Zero cold start for cached workspaces
  • Ideal for high-frequency, short-duration operations

WorkerJavaScriptBackend shares the same scaling properties as Worker-Shell since both run in the Worker isolate without container overhead.

Capabilities and Command Sets

Container Backend Capabilities

Full Linux toolchain access:

  • Run npm install, yarn, pnpm
  • Compile native binaries with gcc, clang, go
  • Invoke any binary on $PATH
  • Network access for fetching dependencies

Worker-Shell Backend Capabilities

Limited to just-bash implemented commands:

  • Text utilities: cat, grep, awk, sed, sort, uniq, wc
  • Data processing: jq, head, tail, cut
  • Custom commands: git, assets (proxied to host DO)

Worker-JavaScript Backend Capabilities

Structured JavaScript execution:

  • Execute arbitrary JS modules with ES imports
  • Receive structured input values
  • Return structured result objects
  • No shell command parsing required

Typical Use Cases

Choose the backend that matches your workload:

  • ContainerBackend — Heavy-weight workloads requiring a real Linux environment: building npm packages, running native binaries, complex build tools, isolated OS environments.

  • WorkerShellBackend — Textual processing, search, transformation, or summarization using shell utilities; scenarios demanding fast startup, cheap scaling, and isolation without container overhead.

  • WorkerJavaScriptBackend — Agent logic best expressed as JavaScript modules; custom business logic requiring library code; situations needing a callable backend that returns structured data rather than parsing stdout.

Code Examples

Container Backend

import { ContainerBackend } from "@cloudflare/computer/backends/container";

const workspace = new Workspace({
  storage: ctx.storage,
  backends: [
    new ContainerBackend({
      // optional: custom loader, env vars, etc.
    })
  ]
});
await workspace.runtime.exec("npm install", { cwd: "/project" });

Worker-Shell Backend

import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";

const workspace = new Workspace({
  storage: ctx.storage,
  backends: [
    new WorkerShellBackend({
      loader: env.LOADER,
      workspace: { binding: "Example", id: ctx.id.toString() },
      ctx,
    })
  ]
});
await workspace.runtime.exec("grep -R 'TODO' src/", { backend: "worker-shell" });

Worker-JavaScript Backend

import { WorkerJavaScriptBackend } from "@cloudflare/computer/backends/worker-javascript";

const workspace = new Workspace({
  storage: ctx.storage,
  backends: [
    new WorkerJavaScriptBackend({
      loader: env.LOADER,
      // `callable: true` lets you pass/receive JSON values
    })
  ]
});

const { result } = await workspace.runtime.exec({
  source: `
    export default async function (input) {
      return { hello: "world", sum: input.a + input.b };
    }
  `,
  input: { a: 3, b: 5 },
  callable: true,
  backend: "worker-javascript"
});
console.log(result); // → { hello: "world", sum: 8 }

Summary

  • ContainerBackend provides full Linux isolation with sync: "remote" and per-session container overhead—ideal for native builds and complex toolchains.

  • WorkerShellBackend delivers instant-starting bash execution with sync: "none" and proxied filesystem access—perfect for text processing at scale.

  • WorkerJavaScriptBackend enables structured JS module execution with sync: "none" and callable interfaces—best for programmatic logic requiring typed inputs and outputs.

All three backends share the same Workspace abstraction and SQLite-backed storage, letting you mix backends within a single application based on task requirements.

Frequently Asked Questions

When should I choose ContainerBackend over the Worker backends?

ContainerBackend is the right choice when you need actual Linux capabilities: compiling native code, running binaries not available in a restricted environment, or using tools like Docker or complex build systems. The seconds-long startup and per-session cost are acceptable tradeoffs for these workloads. According to the Cloudflare Computer source code, this backend is implemented in packages/computer/src/backends/container/index.ts with sync: "remote" requiring explicit VFS synchronization【📄】.

Can I use npm packages with WorkerShellBackend?

No. WorkerShellBackend only exposes commands implemented by just-bash plus the custom git and assets commands. It cannot run npm, node, or install JavaScript dependencies. For npm-based workflows, you must use ContainerBackend or pre-bundle dependencies and execute them via WorkerJavaScriptBackend.

How does WorkerJavaScriptBackend handle module imports?

The backend builds a module graph in packages/computer/src/backends/worker-javascript/module-graph.ts【📄】. You can use standard ES module import syntax within your source string, and the loader resolves dependencies. The executed module receives a structured input object and must export a default function returning the structured result.

Do all backends share the same storage?

Yes. All three backends ultimately persist data to the same host Durable Object's SQLite store. The difference is how they access it: ContainerBackend maintains a separate VFS that syncs remotely, while both Worker backends proxy I/O directly with sync: "none" and no intermediate filesystem layer.

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 →