Configuring Multiple Backends for a Single Workspace in Cloudflare Computer
To configure multiple backends for a single Workspace in Cloudflare Computer, pass a backends map and a defaultBackend identifier to createWorkspace(), then route commands to specific backends using the backend option in exec() calls.
The cloudflare/computer repository enables heterogeneous execution environments through a pluggable backend system. Configuring multiple backends for a single Workspace in Cloudflare Computer allows you to execute commands across Linux containers, bash shells, and JavaScript workers while maintaining a unified filesystem context. The runtime manages each backend through stable string IDs and ensures complete sync isolation between execution environments.
Backend Architecture Overview
A Workspace maintains a backends map ({ [id]: BackendInfo }) and a defaultBackend string that determines fallback behavior. When createWorkspace() initializes the runtime, it stores this configuration to enable dynamic backend selection during command execution.
The Backends Map Structure
Each entry in the backends map requires:
- A unique ID (string key) used for routing
- A description for user-facing tool definitions
- An exec implementation that satisfies the
Backendinterface
Default Backend Resolution
When callers invoke workspace.runtime.exec() without specifying a backend, the system automatically selects the defaultBackend ID. This value is validated at configuration time to ensure it exists within the backends map.
Configuration Implementation
Define your backends and create the Workspace with explicit routing configuration:
import { createWorkspace } from "@cloudflare/computer";
import { ContainerBackend } from "./backends/container";
import { WorkerShellBackend } from "./backends/worker-shell";
/* 1️⃣ Define the backends you want to expose */
const backends = {
// A full Linux container that mounts the workspace via FUSE
container: {
description: "Linux container (real FUSE mount)",
// The concrete implementation that knows how to exec inside the container
exec: ContainerBackend,
},
// A just‑bash shell that runs inside a Dynamic Worker
shell: {
description: "just‑bash shell (Dynamic Worker)",
exec: WorkerShellBackend,
},
// Add more backends here – e.g. a JavaScript worker, a custom RPC, etc.
};
/* 2️⃣ Create the workspace, telling it which backend is the default */
const workspace = await createWorkspace({
backends,
defaultBackend: "container", // ← will be used when `backend` is omitted
});
/* 3️⃣ Use the runtime – callers can now pick a backend explicitly */
await workspace.runtime.exec("npm test", { backend: "shell" });
await workspace.runtime.exec("node build.js", { backend: "container" });
Execution Flow and Routing
The ExecTool in packages/computer/src/tools/exec.ts manages backend selection and validation. When processing an execution request, it extracts the backend ID using the logic backend ?? defaultBackend, verifies that the ID exists in the backends map, and validates callable status through workspace.runtime.isCallable.
Callable backends (such as the JavaScript worker in packages/computer/src/backends/worker-javascript/worker-javascript.ts) can receive structured input payloads and return result objects, while shell-only backends execute raw commands. The ExecTool warns if a non-callable backend receives an input payload, preventing type mismatches at runtime.
Per-Backend Sync Isolation
Each backend maintains independent sync cursors through the DOFS package. In packages/dofs/src/sync/watermarks.ts, the system keys all sync state—including watermarks and fetch cursors—by a composite tuple of (key, backend).
The implementation adds a backend column to both the _vfs_watermark and _vfs_fetch_cursor tables, ensuring that filesystem synchronization progresses independently for each execution environment. The sync driver (packages/rpc/src/sync-driver.ts) propagates the backend identifier down to this storage layer, preventing state interference when running multiple backends concurrently against the same workspace.
Backend Implementation References
The repository provides several reference implementations demonstrating the Backend interface:
- Container Backend:
packages/computer/src/backends/container/index.tsimplements full Linux containerization with FUSE filesystem mounting - Worker Shell Backend:
packages/computer/src/backends/worker-shell/worker-shell.tsprovides a bash environment inside a Dynamic Worker - JavaScript Worker Backend:
packages/computer/src/backends/worker-javascript/worker-javascript.tsdemonstrates callable backend patterns for structured computation
Summary
- Configure multiple backends by passing a
backendsobject anddefaultBackendstring tocreateWorkspace()according to the cloudflare/computer source code - Route execution to specific backends using the
backendoption inworkspace.runtime.exec(), or rely on the default when omitted - Maintain sync isolation through per-backend cursor management in
packages/dofs/src/sync/watermarks.ts, where watermarks are keyed by(key, backend)tuples - Validate callable status via
ExecToollogic inpackages/computer/src/tools/exec.tsto ensure structured inputs only reach backends supporting module execution
Frequently Asked Questions
What is a backend in Cloudflare Computer?
A backend is an execution environment implementation that satisfies the Backend interface, such as a Linux container with FUSE mounting or a Dynamic Worker running bash. Each backend exposes an exec method that the Workspace runtime invokes to run commands or modules within that specific environment.
How does sync isolation work between backends?
The DOFS layer stores synchronization metadata in tables keyed by both resource key and backend ID. Specifically, packages/dofs/src/sync/watermarks.ts adds a backend column to the _vfs_watermark and _vfs_fetch_cursor tables, ensuring each backend maintains independent fetch cursors and watermarks even when accessing the same filesystem paths.
Can I add custom backends beyond containers and shells?
Yes. You can implement any backend that satisfies the Backend interface by providing an object with a unique ID, description, and exec implementation. The packages/computer/src/backends/worker-javascript/worker-javascript.ts file demonstrates how to implement callable backends that process structured input, allowing integration of custom RPC services or specialized compute environments.
What happens if I request a non-existent backend?
The ExecTool in packages/computer/src/tools/exec.ts validates that the requested backend ID exists within the configured backends map before execution. If you specify a backend ID not present in the configuration, the tool rejects the request with a validation error, preventing routing to undefined execution environments.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →