# How to Configure a Workspace with Multiple Backends and Lazy Backend Connections in Cloudflare Computer

> Learn to configure Cloudflare Computer workspaces with multiple backends and lazy backend connections. Optimize performance by deferring RPC target initialization.

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

---

**A Workspace in Cloudflare Computer supports multiple backends by registering them in the `WorkspaceOptions.backends` array and enables lazy connections by deferring RPC target initialization until the first operation, with each backend maintaining independent sync state namespaced by a stable backend ID.**

The Cloudflare Computer repository provides a host-side façade called `Workspace` that orchestrates execution across distributed environments. When you configure a workspace with multiple backends and lazy backend connection capabilities, you gain fine-grained control over resource allocation while maintaining isolated sync cursors for each execution target in the underlying `dofs` database.

## Understanding Workspace Architecture

### Multiple Backend Registration

In [`packages/computer/src/workspace.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts), the `Workspace` class accepts a `backends` array in its constructor options. Each entry must include a stable `id` and a `handle` implementing the backend interface. The first element in this array becomes the **default backend** for operations that do not specify a target.

The underlying `dofs` database schema in [`packages/dofs/src/schema/sync.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/schema/sync.ts) adds a `backend` column to the `_vfs_watermark` and `_vfs_fetch_cursor` tables. Helper functions in [`packages/dofs/src/sync/watermarks.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts) read and write these watermarks with an optional backend argument, defaulting to `DEFAULT_BACKEND_ID` (`"default"`).

### Lazy Connection Mechanics

The lazy behavior is implemented in [`packages/computer/src/stub.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/stub.ts) through the `WorkspaceStub` class. The `connect()` method checks for an existing connection before creating an `RpcTarget` instance. This deferred initialization means no network sockets or Durable Object alarms are established until the first RPC call (such as `pull`, `push`, or `exec`).

The sync driver in [`packages/rpc/src/sync-driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/sync-driver.ts) forwards the optional `backend` argument to sync functions, preserving lazy semantics for each backend independently.

## Configuring Multiple Backends

To register multiple backends, import the appropriate backend factories and pass them to the Workspace constructor:

```typescript
import { Workspace } from "@cloudflare/computer";
import { createContainerBackend } from "@cloudflare/computer/backends/container";
import { createWorkerBackend } from "@cloudflare/computer/backends/worker";

const container = await createContainerBackend({ /* configuration */ });
const worker = await createWorkerBackend({ /* configuration */ });

const ws = new Workspace({
  storage: ctx.storage,
  backends: [
    { id: "container", handle: container },
    { id: "worker", handle: worker },
  ],
});

```

The **first entry** (`"container"` in this example) serves as the default backend. When you call `ws.runtime.exec()` without specifying a backend ID, it routes to this default.

Each backend maintains isolated sync state. A `pull` operation against `"container"` only updates watermarks namespaced to that ID, leaving `"worker"` cursors untouched. This isolation prevents cross-backend contamination and allows independent progress tracking.

## Implementing Lazy Backend Connections

Lazy connections optimize resource usage by deferring network establishment until the first actual operation:

```typescript
// Workspace created - no network traffic yet
const ws = new Workspace({
  storage: ctx.storage,
  backends: [{ id: "container", handle: container }],
});

// First exec triggers lazy connect via WorkspaceStub.connect()
await ws.runtime.exec("container", ["node", "-e", "console.log('hello')"]);

// Subsequent calls reuse the established channel
await ws.runtime.exec("container", ["node", "-e", "console.log('again')"]);

```

The same pattern applies to explicit sync operations:

```typescript
// Triggers connection only for the "worker" backend
await ws.pull("worker");

// Reuses existing connection
await ws.push("worker");

```

This architecture provides **resource efficiency**—unused backends incur no connection overhead—and **failure isolation**, where one unavailable backend does not block operations targeting other backends.

## Advanced Configuration Examples

### Three-Backend Setup

You can combine container, worker, and custom RPC backends in a single workspace:

```typescript
import { createRpcBackend } from "@cloudflare/computer/backends/rpc";

const container = await createContainerBackend({ /* … */ });
const worker = await createWorkerBackend({ /* … */ });
const rpc = await createRpcBackend({ url: "https://example.com/rpc" });

const ws = new Workspace({
  storage: ctx.storage,
  backends: [
    { id: "container", handle: container },
    { id: "worker", handle: worker },
    { id: "rpc", handle: rpc },
  ],
});

```

### Backend-Specific Operations

Target specific backends explicitly to control where code executes:

```typescript
// Pull only from the RPC backend
await ws.pull("rpc");

// Execute on default backend (first entry)
await ws.runtime.exec(["bash", "-c", "echo default"]);

```

### Inspecting Per-Backend Sync State

Monitor individual backend progress using the `dofs` database helpers:

```typescript
import { readFetchCursor, readWatermark } from "@cloudflare/dofs";

const db = ws.db;

console.log(
  "Container cursor:",
  readFetchCursor(db, "container"),
  "Worker cursor:",
  readFetchCursor(db, "worker")
);

```

## Summary

- Register multiple backends by passing an array to `WorkspaceOptions.backends` in [`packages/computer/src/workspace.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/workspace.ts), where the first entry becomes the default.
- Each backend receives a stable ID that namespaces sync state in the `dofs` database via the `backend` column in `_vfs_watermark` and `_vfs_fetch_cursor` tables.
- Lazy connections are handled by `WorkspaceStub.connect()` in [`packages/computer/src/stub.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/stub.ts), which initializes `RpcTarget` instances only upon first RPC invocation.
- The sync driver in [`packages/rpc/src/sync-driver.ts`](https://github.com/cloudflare/computer/blob/main/packages/rpc/src/sync-driver.ts) preserves per-backend lazy semantics by forwarding the optional `backend` argument.
- This design ensures resource efficiency and failure isolation across distributed execution environments.

## Frequently Asked Questions

### How do I set a default backend when configuring multiple backends?

The default backend is automatically assigned to the **first element** in the `backends` array passed to the `Workspace` constructor. Any operation that omits the backend ID parameter, such as `ws.runtime.exec()`, will route to this default. You can override this behavior by explicitly passing a backend ID string as the first argument to most workspace methods.

### What happens to sync state when using multiple backends?

Each backend maintains completely isolated sync state. The `dofs` schema stores watermarks and fetch cursors with a `backend` column identifier, ensuring that a `pull` or `push` operation against one backend never interferes with another's progress tracking. This isolation is managed by helper functions in [`packages/dofs/src/sync/watermarks.ts`](https://github.com/cloudflare/computer/blob/main/packages/dofs/src/sync/watermarks.ts) that accept an optional backend parameter.

### When exactly does a lazy backend connection get established?

A connection is established on the **first RPC call** targeting that specific backend, such as `exec`, `pull`, or `push`. The `WorkspaceStub` class in [`packages/computer/src/stub.ts`](https://github.com/cloudflare/computer/blob/main/packages/computer/src/stub.ts) checks for an existing connection in its `connect()` method and only initializes the `RpcTarget` when needed. If a backend is never invoked, it remains disconnected and consumes no network resources or Durable Object alarms.

### Can I mix different backend types in the same workspace?

Yes, you can combine container backends, worker backends, and custom RPC backends within a single `Workspace` instance. Each backend type implements the same interface and registers with a unique ID, allowing you to route specific workloads to the most appropriate execution environment while maintaining unified sync management through the `dofs` database.