# How Cloudflare Computer's WorkspaceRuntime Routes exec Requests to Container, Worker‑Shell, and Worker‑JavaScript Backends

> Discover how Cloudflare Computer's WorkspaceRuntime routes exec requests to container, worker-shell, and worker-javascript backends using its unified interface.

- Repository: [Cloudflare/computer](https://github.com/cloudflare/computer)
- Tags: internals
- Published: 2026-08-07

---

**Cloudflare Computer's `WorkspaceRuntime` routes `exec` requests through a unified interface that dispatches container and worker‑shell calls via RPC-based `CommandExecutor` handles while executing worker‑javascript code through native in‑process module handles.**

Cloudflare Computer provides a unified execution surface that abstracts diverse compute environments behind a single API. In the `cloudflare/computer` repository, the `WorkspaceRuntime` class orchestrates how `exec` calls reach their destination—whether that's a containerized process, a Worker Durable Object shell, or native JavaScript execution. Understanding this routing mechanism reveals how the platform maintains a consistent developer experience across fundamentally different backend architectures.

## Backend Architecture: Command vs. Module Backends

The routing system distinguishes between two fundamental backend types registered in [`packages/computer/src/workspace.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts).

**Command-backends** implement the `Backend.connect` method to return a `BackendHandle` exposing an RPC-based `shell` interface. Both the **container** (`computerd` FUSE driver) and **worker‑shell** backends use this pattern. They rely on `CommandExecutor` to forward `exec` calls over Cap'n Web RPC channels defined in [`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md).

**Module-backends** return a native `WorkspaceModuleBackendHandle` that runs code in‑process without RPC overhead. The **worker‑javascript** backend uses this approach, allowing direct JavaScript execution within the Worker environment.

## The Execution Flow

When you invoke `Workspace.runtime.exec`, the system follows a deterministic resolution path:

1. **Backend Resolution** – `WorkspaceRuntime` receives an optional `backend` identifier. If omitted, it defaults to the first registered backend:

```typescript
const backend = this.#options.resolveBackendId(requested);

```

2. **Handle Acquisition** – The system branches based on backend type:
   - **Command-backends** (container, worker‑shell) → `Workspace.#shellFor` creates a `CommandExecutor` wrapping the RPC `shell` stub
   - **Module-backends** (worker‑javascript) → `Workspace.#moduleHandleFor` returns a native module handle

3. **Execution Dispatch** – The selected handle's `exec` method receives the source string, working directory, environment variables, and stdin. It returns a `ModuleExecutionEnvelope` containing an execution ID, event stream (stdout/stderr/exit), and sync object.

4. **Result Wrapping** – `WorkspaceRuntime.exec` in [`packages/computer/src/runtime/runtime.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/runtime/runtime.ts) constructs a `WorkspaceRuntimeExecHandle` that streams events lazily and assembles the final `WorkspaceRuntimeResult` through its `result()` method.

5. **Synchronization Bracketing** – Every execution is automatically wrapped with `Workspace.push` and `Workspace.pull` calls for the selected backend, ensuring the local SQLite store (`@cloudflare/dofs`) remains synchronized with remote state.

## Backend-Specific Routing Logic

### Container Backend (`computerd`)

When routing to a container backend, `Workspace.#backendHandleFor` resolves the backend ID to a command-backend handle. The associated `BackendHandle` contains an `rpc.shell` endpoint that communicates with the `computerd` binary—the FUSE driver implementation found in [`packages/computer/src/fuse/driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fuse/driver.ts). The `CommandExecutor` forwards the `exec` call over the Cap'n Web RPC contract to the remote process.

### Worker‑Shell Backend

Worker‑shell routing follows the identical command-backend path as containers, but the RPC target is a Cloudflare Worker Durable Object running a thin shell implementation. Located in [`packages/computer/src/backend/worker-shell.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backend/worker-shell.ts), this backend exposes the same `shell` RPC interface as the container driver. The `CommandExecutor` transparently forwards requests to the Worker's RPC endpoint, executing commands inside the Worker environment.

### Worker‑JavaScript Backend

For worker‑javascript execution, the backend ID maps to a module-backend through [`packages/computer/src/backend/worker-javascript.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backend/worker-javascript.ts). Because `isModuleBackend(backend)` returns `true`, the system invokes `Workspace.#moduleHandleFor` rather than the shell path. This bypasses RPC entirely—the JavaScript module runs in‑process through the native `WorkspaceModuleBackendHandle.exec` implementation.

## Code Implementation Example

The following example demonstrates registering multiple backends and routing `exec` requests to each:

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

const ws = new Workspace({
  storage: ctx.storage,
  backends: [
    // Container backend (exec runs inside the `computerd` process)
    { 
      id: "container", 
      type: "container", 
      connect: containerConnect,
      callable: false 
    },
    // Worker‑Shell backend (exec runs inside a Worker Durable Object)
    { 
      id: "shell", 
      type: "worker-shell", 
      connect: shellConnect,
      callable: false 
    },
    // Worker‑JavaScript backend (native JS module execution)
    { 
      id: "js", 
      type: "worker-javascript", 
      connect: jsConnect, 
      callable: true 
    },
  ],
});

// Route to container via RPC
await ws.runtime.exec('echo "Hello from container"', { backend: "container" });

// Route to native JavaScript execution (no RPC)
await ws.runtime.exec('console.log("Hello from JS")', { backend: "js", input: "utf8" });

// Route to Worker shell via RPC
await ws.runtime.exec('ls -la', { backend: "shell" });

```

## Key Source Files

- **[`packages/computer/src/workspace.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts)** – Core `Workspace` class implementing backend registration, handle caching (`#shellFor`, `#moduleHandleFor`), and push/pull synchronization logic.
- **[`packages/computer/src/runtime/runtime.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/runtime/runtime.ts)** – `WorkspaceRuntime` implementation routing `exec`, `getExec`, `killExec`, and `disposeExec` to appropriate backend handles.
- **[`packages/computer/src/backend/worker-shell.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backend/worker-shell.ts)** – Command-backend implementation for Worker‑Shell providing the RPC `shell` stub.
- **[`packages/computer/src/backend/worker-javascript.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backend/worker-javascript.ts)** – Module-backend implementation for native JavaScript execution.
- **[`packages/computer/src/fuse/driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fuse/driver.ts)** – `computerd` RPC driver for container backend communication.
- **[`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md)** – Cap'n Web RPC contract specification for `shell`, `sync`, and related interfaces.

## Summary

- **Cloudflare Computer** unifies container, worker‑shell, and worker‑javascript execution behind a single `Workspace.runtime.exec` API.
- **Command-backends** (container, worker‑shell) route through `CommandExecutor` using Cap'n Web RPC to remote processes or Worker Durable Objects.
- **Module-backends** (worker‑javascript) execute natively in‑process via `WorkspaceModuleBackendHandle`, eliminating RPC overhead.
- **Backend resolution** occurs through `Workspace.#options.resolveBackendId`, with handle acquisition branching between `#shellFor` and `#moduleHandleFor`.
- **Automatic synchronization** via `push`/`pull` bracketing keeps the local SQLite store consistent with remote backend state.

## Frequently Asked Questions

### How does WorkspaceRuntime determine which backend to use for an exec request?

`WorkspaceRuntime` calls `this.#options.resolveBackendId(requested)` where `requested` is the optional `backend` parameter passed to `exec`. If no backend is specified, it defaults to the first registered backend in the `Workspace` configuration. The resolved ID then determines whether the system acquires a command handle via `#shellFor` or a module handle via `#moduleHandleFor`.

### What is the technical difference between command-backends and module-backends?

Command-backends implement `Backend.connect` to return a handle exposing an RPC `shell` interface, requiring serialization of commands across process boundaries via `CommandExecutor`. Module-backends return `WorkspaceModuleBackendHandle` objects that implement `exec` natively, allowing direct in‑process execution without Cap'n Web RPC serialization. This distinction determines whether your code runs remotely (containers, worker‑shells) or locally within the Worker (worker‑javascript).

### How does the container backend communicate with the computerd process?

The container backend uses the FUSE driver implementation in [`packages/computer/src/fuse/driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/fuse/driver.ts) to establish an RPC connection. When `Workspace.#shellFor` creates a `CommandExecutor` for a container backend, it wraps the `rpc.shell` stub from the `BackendHandle`. The executor serializes the `exec` call over the Cap'n Web protocol defined in [`docs/08_capnweb_interface.md`](https://github.com/cloudflare/computer/blob/main/docs/08_capnweb_interface.md), transmitting it to the remote `computerd` process managing the container filesystem.

### Can I execute JavaScript code without the RPC overhead of container or shell backends?

Yes. By routing your `exec` request to a `worker-javascript` backend, the system uses `Workspace.#moduleHandleFor` to obtain a native `WorkspaceModuleBackendHandle`. This backend type, implemented in [`packages/computer/src/backend/worker-javascript.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/backend/worker-javascript.ts), executes JavaScript modules directly within the Worker process. No RPC serialization or remote calls occur, resulting in lower latency execution for JavaScript workloads.