What Is the Role of Durable Objects in Cloudflare OS? Architecture and Implementation

Durable Objects serve as the foundational stateful primitive in Cloudflare OS, providing isolated, strongly consistent storage and compute for every workspace, user gadget, gatekeeper collection, and administrative setting across the platform.

Cloudflare OS implements an "operating-system-like" experience entirely on top of Cloudflare Durable Objects (DOs), leveraging their guarantee of single-authoritative instances and strong consistency per identifier. As implemented in the cloudflare/cloudflare-os repository, these serverless primitives function as the durable backbone for workspace isolation, application sandboxing, and user-specific persistence. Understanding how Durable Objects in Cloudflare OS are architected reveals how the platform achieves real-time collaboration and strict tenant isolation without cross-contamination.

Core Architectural Roles of Durable Objects

The platform utilizes Durable Objects for five distinct architectural purposes, each addressing specific requirements for state management and isolation.

Workspace Isolation and Persistence

Each user workspace operates as a dedicated Durable Object that stores the complete state of the workspace, including documents, gadgets, and user-specific settings. Because Durable Objects offer strong consistency guarantees, real-time collaboration on a workspace is implemented by reading and writing to the same authoritative object from multiple concurrent clients.

The OverseerDurableObject class defined in packages/workshop-backend/src/overseer.ts (line 9689) functions as the kernel for a workspace. This DO maintains the canonical state for all workspace operations, ensuring that all connected clients observe the same data regardless of which edge location they connect through.

Gadget Execution Sandbox

Every Gadget—the user-created applications within Cloudflare OS—runs inside a Dynamic Worker Facet attached to the workspace DO. The facet itself is implemented as a Durable Object subclass named Gadget located in packages/workshop-backend/src/agent.ts (line 693).

This Gadget DO holds the application's code, its persistent storage, and its runtime sandbox. By executing each user application within its own Durable Object, Cloudflare OS ensures complete isolation between tenants; user-generated code runs in isolated contexts without any cross-tenant data leakage or resource contention.

Gatekeeper State and Capability Management

Gatekeepers, which serve as capability-based adapters for external services, maintain per-user accounts and collection metadata within dedicated Durable Objects. The ContextCollectionDurableObject in packages/gatekeeper-context/src/context-collection.ts (line 132) exemplifies this pattern, storing a user's private or public collection of documents that agents can access as observations.

These Gatekeeper DOs expose a clean RPC surface to agents while maintaining strict data isolation per account. The persistent storage provided by state.storage ensures that collection metadata survives worker restarts and evictions.

Admin Configuration

Global administrative configuration—the kernel settings affecting every workspace—resides in a single Durable Object named AdminSettings defined in packages/workshop-backend/src/admin-settings.ts (line 57). Updates to the admin panel write directly to this DO, and all workers fetch the latest configuration via a cheap KV read that mirrors the DO's state, ensuring consistent behavior across the platform without polling a central database.

User-Level Persistence

Individual user data, including profiles and personal settings, lives in its own Durable Object: the UserDurableObject class found in packages/workshop-backend/src/user.ts (line 282). This architecture isolates user-specific data from other users while allowing the kernel to fetch it quickly through the Durable Object's deterministic routing. No additional namespacing is required because the state.storage is automatically scoped to that specific user instance.

Implementation Examples from the Source Code

The following patterns demonstrate how Cloudflare OS interacts with these Durable Objects in production code.

Accessing the Workspace DO from a Request Handler

When handling incoming requests, workers obtain a stub to the specific workspace Durable Object using the binding declared in wrangler.toml:

// In a Worker (backend) request handler
export default {
  async fetch(request: Request, env: Env) {
    // The binding name is declared in wrangler.toml as `WORKSPACE`
    const workspaceDO = env.WORKSPACE.get(env.USER_ID); // USER_ID is a stable identifier

    // Call a method defined on the OverseerDurableObject
    const result = await workspaceDO.fetch("GET", "/api/state");
    const state = await result.json();
    return new Response(JSON.stringify(state));
  },
};

The get call returns a stub to the specific workspace DO, and the RPC call routes to the OverseerDurableObject implementation in packages/workshop-backend/src/overseer.ts.

Creating a New Gadget Inside a Workspace

User applications are instantiated as new Durable Objects dynamically:

// In the client-side code (frontend) when a user requests a new gadget
async function createGadget(name: string, code: string) {
  const resp = await fetch("/api/gadgets", {
    method: "POST",
    body: JSON.stringify({ name, code }),
    headers: { "Content-Type": "application/json" },
  });
  const { gadgetId } = await resp.json();

  // The returned ID can be used to talk to the Gadget DO later:
  const gadgetDO = env.GADGETS.get(gadgetId);
  await gadgetDO.fetch("POST", "/run", { body: JSON.stringify({ action: "init" }) });
}

The Gadget class in packages/workshop-backend/src/agent.ts extends DurableObject, giving each gadget isolated state and execution context.

Storing Data in the UserDurableObject

Per-user persistence requires no manual partitioning because the Durable Object itself provides the isolation boundary:

// Example method inside packages/workshop-backend/src/user.ts
export class UserDurableObject extends DurableObject<Cloudflare.Env> {
  async fetch(request: Request) {
    const url = new URL(request.url);
    if (url.pathname === "/profile") {
      const profile = await this.state.storage.get<UserProfile>("profile");
      return new Response(JSON.stringify(profile ?? {}));
    }
    // …other routes…
  }
}

Because the DO instance is unique per user, the state.storage is automatically scoped to that user without additional namespacing logic.

Gatekeeper Collection Storage

Gatekeepers utilize Durable Objects to maintain persistent collections accessible to agents:

// Inside packages/gatekeeper-context/src/context-collection.ts
export class ContextCollectionDurableObject extends DurableObject<Cloudflare.Env> {
  async fetch(request: Request) {
    // Read/write collection items – automatic persistence across restarts
    const items = await this.state.storage.get<Record<string, any>>("items");
    // Return items to the agent as observations
    return new Response(JSON.stringify(items ?? {}));
  }
}

These Gatekeeper DOs provide durable storage for context collections while exposing them to the agent system as observable state.

Summary

  • Durable Objects in Cloudflare OS function as the platform's complete state layer, replacing traditional databases for workspace, user, and application state.
  • The OverseerDurableObject in packages/workshop-backend/src/overseer.ts provides the authoritative kernel for each workspace, enabling real-time collaboration through strong consistency.
  • Gadget DOs in packages/workshop-backend/src/agent.ts create isolated execution sandboxes for user code, preventing cross-tenant leakage.
  • Gatekeeper DOs like ContextCollectionDurableObject manage external service adapters with persistent per-account storage.
  • UserDurableObject and AdminSettings DOs provide durable isolation boundaries for personal data and global configuration, respectively.

Frequently Asked Questions

How does Cloudflare OS use Durable Objects for workspace isolation?

Cloudflare OS assigns each workspace a dedicated OverseerDurableObject instance, identified by a stable user ID. When clients connect, they receive a stub to this specific DO, ensuring all reads and writes target the same authoritative state. This pattern guarantees strong consistency across distributed clients while maintaining complete isolation between different workspaces, as each workspace exists in its own Durable Object instance with separate storage and compute resources.

What is the role of the Gadget Durable Object in application security?

The Gadget Durable Object class, defined in packages/workshop-backend/src/agent.ts, creates an isolated execution environment for each user-created application. By running gadget code within a dedicated DO, Cloudflare OS ensures that user applications cannot access other tenants' data or interfere with the broader workspace kernel. The DO's state.storage provides sandboxed persistence for the application's data, while the facet architecture prevents unauthorized access to the parent workspace state.

How are Gatekeeper collections persisted in Durable Objects?

Gatekeepers utilize specialized Durable Objects such as ContextCollectionDurableObject (found in packages/gatekeeper-context/src/context-collection.ts) to store per-account collection metadata and documents. These DOs maintain persistent state across worker restarts using state.storage, and they expose RPC interfaces that allow agents to retrieve collections as observations. This architecture ensures that user integrations with external services maintain durable, isolated state without requiring external databases.

How does the AdminSettings Durable Object manage global configuration?

The AdminSettings Durable Object in packages/workshop-backend/src/admin-settings.ts serves as the single source of truth for platform-wide configuration. When administrators update settings through the admin panel, changes are written to this DO, and the state is mirrored to KV for fast global reads. This pattern ensures all workers receive consistent configuration updates without the latency of querying a centralized database on every request.

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 →