# How to Enable Command and Code Execution by Adding Backends to Workspace in Cloudflare Computer

> Learn to enable command and code execution in Cloudflare Computer Workspaces by adding backends. Route execution to Container, Shell, or JavaScript runtimes easily.

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

---

**To enable command and code execution in a Cloudflare Computer Workspace, add backends to the `backends` array when initializing the Workspace using the `withWorkspace` mix-in, then invoke `workspace.runtime.exec()` with the `backend` option to route execution to Container, Shell, or JavaScript runtimes.**

Cloudflare Computer's `Workspace` provides a virtual filesystem that can execute shell commands and evaluate code through pluggable **backends**. Each backend implements a distinct execution surface—ranging from lightweight shells to full Linux containers—and is registered under a stable identifier when the workspace is created. This architecture allows developers to enable command and code execution by adding backends to Workspace configurations according to their specific runtime requirements.

## Understanding Workspace Backend Architecture

The Workspace architecture separates storage from execution, allowing multiple backends to coexist without interference.

### The WorkspaceBackend Interface

Every backend must conform to the `WorkspaceBackend` interface defined in the RPC layer at [[`packages/rpc/src/interface.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/interface.ts)](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/interface.ts). This contract ensures that all backends expose a consistent surface for the Workspace to invoke. Internally, sync cursors are scoped per-backend (see the watermarks implementation in [[`packages/dofs/src/sync/watermarks.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts)](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts)), enabling concurrent operations across different execution environments without state collision.

### Runtime Execution Flow

When you call `workspace.runtime.exec(source, { backend })`, the system resolves the execution target via `workspaceBackendForCommand`. The `backend` option selects which registered backend handles the request; if omitted, the runtime defaults to the first backend in the array. The selected backend receives the source—whether a shell string or JavaScript module—and executes it within its isolated environment.

## Available Backend Types

Cloudflare Computer provides three primary backend implementations, each optimized for different workload characteristics.

### Container Backend

The **Container backend** projects the workspace's SQLite state into a sandbox container and mounts it via FUSE, providing a full Linux userland capable of running any shell command or binary. This backend is ideal for heavy-weight operations requiring system packages or native binaries. Implementation resides in [[`packages/computer/src/backends/container/index.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/container/index.ts)](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/container/index.ts).

### Worker-Shell Backend

The **Worker-Shell backend** runs the lightweight *just-bash* shell inside a Dynamic Worker. It forwards `shell.exec` calls to that worker while maintaining all state inside the original Durable Object, offering a fast, lightweight option for simple shell operations. Implementation resides 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)](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/worker-shell/worker-shell.ts).

### Worker-JavaScript Backend

The **Worker-JavaScript backend** evaluates ECMAScript modules in a Dynamic Worker, exposing a structured RPC surface including `fs`, `git`, and `artifacts` APIs. This backend is optimal for JavaScript/TypeScript automation scripts that need structured access to workspace resources. Implementation resides in [[`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)](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/worker-javascript/worker-javascript.ts).

## Adding Backends to Your Workspace

You add backends by passing a `backends` array to the `withWorkspace` mix-in when defining your Durable Object class. The mix-in stores this array on the `Workspace` prototype, and the runtime automatically connects to a backend the first time it is addressed.

```typescript
import { withWorkspace } from "@cloudflare/computer";
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
import { CloudflareContainerBackend } from "@cloudflare/computer/backends/container";
import curl from "@cloudflare/computer/shell/curl";
import jq from "@cloudflare/computer/shell/jq";

export class MyDO extends withWorkspace(
  class extends DurableObject<Env> {},
  (self) => {
    const { ctx, env } = self as unknown as { ctx: DurableObjectState; env: Env };
    return {
      storage: ctx.storage as unknown as DurableObjectStorageLike,
      backends: [
        // Shell backend for quick commands
        new WorkerShellBackend({
          loader: env.LOADER,
          workspace: { binding: "MyDO", id: ctx.id.toString() },
          ctx,
          commands: [curl, jq],
        }),
        // Container backend for full Linux environment
        new CloudflareContainerBackend({
          workspace: { binding: "MyDO", id: ctx.id.toString() },
          env,
        }),
      ],
    };
  }
) {}

```

*Source:* [[`examples/worker-shell/src/index.ts`](https://github.com/cloudflare/computer/blob/main/examples/worker-shell/src/index.ts)](https://github.com/cloudflare/computer/blob/main/examples/worker-shell/src/index.ts)

## Executing Commands and Code

Once backends are registered, you route execution to specific backends using the `backend` option in `workspace.runtime.exec()`.

### Running Shell Commands

Target the shell backend (identified as `'shell'` by default) to execute bash commands:

```typescript
import { getWorkspace } from "@cloudflare/computer";

const ws = await getWorkspace(env.MyDO);
const result = await ws.runtime.exec('ls -la /workspace', { backend: 'shell' });
console.log(result.stdout);

```

### Evaluating JavaScript Modules

Target the JavaScript backend to evaluate ECMAScript modules with access to workspace APIs:

```typescript
import { getWorkspace } from "@cloudflare/computer";

const ws = await getWorkspace(env.MyDO);
const source = `
export default async function () {
  const { readFile } = await import('node:fs/promises');
  const data = await readFile('/workspace/example.txt', 'utf8');
  return { data };
}
`;
const { result } = await ws.runtime.exec(source, { backend: 'javascript' });
console.log(result.data);

```

### Executing Container Commands

Use the container backend for operations requiring system packages or heavy computation:

```typescript
const ws = await getWorkspace(env.MyDO);
await ws.runtime.exec('apt-get update && apt-get install -y ffmpeg', {
  backend: 'container',
});

```

## Error Handling and Backend Selection

When `workspace.runtime.exec` is invoked, the runtime helper `workspaceBackendForCommand` (demonstrated in the *think-compare-runtimes* example) resolves the appropriate backend based on the provided option. Errors thrown during execution are wrapped as `WorkspaceFsError` instances with a `code` field, allowing callers to branch on specific error conditions like `ENOENT` or `EUNKNOWN_HASH`.

## Summary

- **Backend Architecture**: Cloudflare Computer Workspaces support multiple execution surfaces through the `WorkspaceBackend` interface, with per-backend sync cursors ensuring isolation.
- **Registration**: Add backends via the `backends` array in the `withWorkspace` mix-in options, supplying configuration for each backend type.
- **Execution**: Route commands to specific backends using `workspace.runtime.exec(source, { backend: 'shell' | 'javascript' | 'container' })`.
- **Error Handling**: Execution failures return `WorkspaceFsError` objects with specific error codes for programmatic handling.
- **Key Files**: Core logic resides in [[`packages/computer/src/workspace.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts)](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts), with backend implementations in [`packages/computer/src/backends/`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backends/).

## Frequently Asked Questions

### How do I choose between the Worker-Shell and Container backends?

**Use the Worker-Shell backend for lightweight, fast-executing bash commands that don't require system packages**, as it runs *just-bash* inside a Dynamic Worker with minimal overhead. **Use the Container backend when you need a full Linux userland**, system package managers like `apt-get`, or native binaries, as it provides a sandboxed container environment via FUSE.

### Can I use multiple backends simultaneously in the same Workspace?

Yes, the Workspace architecture supports multiple concurrent backends. Each backend maintains independent sync cursors (as implemented in [[`packages/dofs/src/sync/watermarks.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts)](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts)), allowing them to coexist without interfering with each other's progress. You can route different commands to different backends within the same Durable Object instance.

### What is the default backend if I don't specify one in `exec()`?

If you omit the `backend` option in `workspace.runtime.exec()`, the runtime uses the **first backend in the `backends` array** as the default. This is determined by the order in which you instantiate backends when configuring the `withWorkspace` mix-in.

### How do I add custom shell commands to the Worker-Shell backend?

Pass an array of command modules to the `commands` property when instantiating `WorkerShellBackend`. For example, import `curl` and `jq` from `@cloudflare/computer/shell/*` and include them in the configuration object, as shown in the [`examples/worker-shell/src/index.ts`](https://github.com/cloudflare/computer/blob/main/examples/worker-shell/src/index.ts) implementation.