# Understanding Durable Objects in Cloudflare OS Gadgets: Architecture and Implementation

> Explore Durable Objects in Cloudflare OS Gadgets. Discover how they provide persistent storage, isolation, and RPC for every long-living entity, enabling robust stateful compute.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: architecture
- Published: 2026-09-05

---

**Durable Objects serve as the fundamental stateful compute primitive in Cloudflare OS Gadgets, providing persistent storage, capability-based isolation, and type-safe cross-worker RPC for every long-living entity in the platform.**

Cloudflare OS Gadgets is an open-source framework for building distributed applications on Cloudflare's edge network. According to the cloudflare/cloudflare-os repository, Durable Objects form the architectural foundation of this system, powering user accounts, administrative settings, and scheduled workflows. This analysis explores the specific implementation patterns found in the source code, from the `UserDurableObject` class in [`packages/workshop-backend/src/user.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/user.ts) to the facet-based concurrency in [`packages/gatekeeper-scheduler/src/schedule-driver.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-scheduler/src/schedule-driver.ts).

## Persistent State Management in User Accounts

In Cloudflare OS Gadgets, each user is backed by a dedicated Durable Object that owns a `DurableObjectStorage` instance. This storage survives worker restarts and can be queried from any worker within the same deployment, ensuring credentials and preferences remain available across edge locations.

The `UserDurableObject` class in [`packages/workshop-backend/src/user.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/user.ts) demonstrates this pattern by storing credentials, preferences, and capability records. Similarly, the `UserAccount` implementation in [`packages/gatekeeper-google/src/google.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-google/src/google.ts) leverages this durability to ensure OAuth tokens and user metadata persist through worker upgrades or crashes.

## Capability-Based Security Isolation

Durable Objects enforce strict security boundaries through unique identifiers and isolated storage namespaces. Each DO receives a distinct `DurableObjectId`, guaranteeing that data cannot be accessed by other users or workers without an explicit capability grant.

The administrative layer relies on this isolation. The `AdminSettings` class in [`packages/workshop-backend/src/admin-settings.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/admin-settings.ts) stores deployment-wide configuration behind a durable capability obtained via `AuthenticatedApi.getAdminApi()`. Likewise, the `OverseerDurableObject` in [`packages/workshop-backend/src/overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts) protects global workspace state, orchestrating gadget execution while maintaining security boundaries between tenants.

## Cross-Worker RPC Communication

Cloudflare OS Gadgets utilizes the Cap'n Web RPC system to route method calls to Durable Object instances. This mechanism automatically handles promise pipelining and stub disposal, allowing agents and frontends to interact with DOs through well-typed interfaces rather than raw storage operations.

The `ContextCollectionDurableObject` in [`packages/gatekeeper-context/src/context-collection.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/context-collection.ts) exposes RPC-typed sessions that agents consume via methods like `session = await gatekeeper.getSession()`. This pattern ensures that the admin API, agent code, and frontend UI all communicate through consistent, type-safe stubs defined in the abstract `DurableObject` base class (see [`packages/workshop-backend/worker-configuration.d.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/worker-configuration.d.ts)).

## Scalable State Sharing with Facets

For fine-grained concurrency within a single Durable Object, the platform implements **facets**—named sub-objects that function as micro-services sharing the same DO context. This pattern allows different logical components to maintain isolated state while benefiting from the DO's durability guarantees.

The scheduler gatekeeper demonstrates this approach in [`packages/gatekeeper-scheduler/src/schedule-driver.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-scheduler/src/schedule-driver.ts). The `ScheduleDriver` class registers persistent callbacks for workspace scheduling, while individual facets provide per-schedule isolation. This design enables complex, concurrent workflows without spawning separate DO instances.

## Implementation Examples from the Source Code

The following patterns illustrate how Durable Objects are defined and consumed throughout the cloudflare/cloudflare-os repository.

### Defining a Basic Durable Object

The `ExampleDurableObject` class in [`packages/gatekeeper-example/src/example-do.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-example/src/example-do.ts) shows the minimal implementation required to extend the base `DurableObject` class and interact with persistent storage:

```typescript
export class ExampleDurableObject extends DurableObject<Cloudflare.Env> {
  async fetch(request: Request) {
    const value = await this.ctx.storage.get<string>("greeting");
    return new Response(value ?? "Hello, world!");
  }

  async setGreeting(greeting: string) {
    await this.ctx.storage.put("greeting", greeting);
  }
}

```

This class uses the `ctx.storage` API to read and write values that persist across requests and worker restarts.

### Accessing a DO from a Worker

Workers obtain RPC stubs to Durable Objects through the namespace's `get` method. The `UserDurableObject` implementation demonstrates this pattern:

```typescript
export class UserDurableObject extends DurableObject<Cloudflare.Env> {
  // ...implementation...
}

// Somewhere in a request handler
const userDO = env.UserDurableObject.get(env.UserDurableObject.idFromName(userId));
const stub = await userDO;                     // RPC stub
await stub.setPreference({ theme: "dark" });   // Calls a DO method

```

The `idFromName` method generates a deterministic identifier from a string, ensuring the same DO instance is retrieved across different worker invocations.

### Fetching Gatekeeper Sessions

Agents consume Durable Objects through session stubs provided by gatekeeper implementations. The frontend session management code illustrates this interaction:

```typescript
import { getGatekeeperClassFor } from "packages/workshop-backend/src/user.ts";

async function obtainSession(env) {
  const GatekeeperClass = await getGatekeeperClassFor("GATEKEEPER_CONTEXT");
  const gatekeeper = env.GATEKEEPER_CONTEXT.get(env.GATEKEEPER_CONTEXT.idFromName("default"));
  const session = await gatekeeper.getSession(); // Returns a typed session stub
  return session;
}

```

This pattern enforces the "ambient capability" model, where access to DO functionality is granted through typed sessions rather than direct storage manipulation.

### Implementing Facets for Concurrency

The `ScheduleDriver` class demonstrates advanced facet usage for isolating schedule-specific logic:

```typescript
export class ScheduleDriver extends DurableObject<Cloudflare.Env> {
  async schedule(name: string, cron: string) {
    const facet = this.ctx.facets.get("ScheduleFacet", () => ({
      id: undefined,
      class: ScheduleFacet,
    }));
    await facet.add(name, cron);
  }
}

```

Facets allow the scheduler to maintain multiple isolated callback registries within a single Durable Object, optimizing resource usage while preserving logical separation.

## Key Architectural Files

The following files define the core Durable Object infrastructure in Cloudflare OS Gadgets:

- **[`packages/workshop-backend/worker-configuration.d.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/worker-configuration.d.ts)** – Defines TypeScript typings for `DurableObject`, `DurableObjectNamespace`, and RPC helpers.

- **[`packages/workshop-backend/src/user.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/user.ts)** – Implements `UserDurableObject`, the central example of per-user persistent state management.

- **[`packages/workshop-backend/src/overseer.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/overseer.ts)** – Contains the `OverseerDurableObject` that orchestrates gadget execution and maintains global workspace state.

- **[`packages/workshop-backend/src/admin-settings.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/admin-settings.ts)** – Stores deployment-wide admin configuration behind a durable capability check.

- **[`packages/gatekeeper-context/src/context-collection.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/context-collection.ts)** – Provides the DO-backed storage layer for the Context gatekeeper's collections.

- **[`packages/gatekeeper-context/src/user-library.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/user-library.ts)** – Manages per-user private collections via dedicated DO instances.

- **[`packages/gatekeeper-context/src/registry-do.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-context/src/registry-do.ts)** – Registers public collections across deployments as read-only Durable Objects.

- **[`packages/gatekeeper-scheduler/src/schedule-driver.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-scheduler/src/schedule-driver.ts)** – Implements persistent scheduling callbacks using DO facets.

## Summary

- **Durable Objects provide the fundamental stateful compute layer** for Cloudflare OS Gadgets, handling everything from user authentication to administrative configuration.
- **Each DO maintains isolated storage** through unique `DurableObjectId` instances and `DurableObjectStorage` APIs that survive worker restarts.
- **Capability-based security** enforces boundaries between users and admin functions, with sensitive operations protected behind explicit capability grants in files like [`admin-settings.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/admin-settings.ts).
- **Type-safe RPC communication** enables cross-worker interaction through Cap'n Web RPC stubs, exposed via methods like `getSession()` in gatekeeper implementations.
- **Facets enable fine-grained concurrency** within single DO instances, as demonstrated by the `ScheduleDriver`'s per-schedule isolation pattern.

## Frequently Asked Questions

### What is the relationship between Durable Objects and gatekeepers in Cloudflare OS?

Gatekeepers are logical security boundaries or service interfaces that are implemented as Durable Objects. Each gatekeeper defines one or more DO classes—such as `ContextCollectionDurableObject` or `ScheduleDriver`—that model specific entities. The Durable Object provides the persistent state and RPC interface that the gatekeeper exposes to agents and the frontend UI.

### How does data persistence work across worker restarts?

Durable Objects in Cloudflare OS use the `DurableObjectStorage` API, which automatically replicates state across Cloudflare's edge datacenters. When a worker restarts or crashes, the DO's storage remains intact because it is maintained separately from the worker process. Files like [`packages/gatekeeper-google/src/google.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-google/src/google.ts) demonstrate how OAuth credentials persist through these events.

### What role do facets play in Durable Object architecture?

Facets are named sub-objects within a single Durable Object that act like independent micro-services. They allow the system to isolate different logical contexts—such as individual schedules in [`packages/gatekeeper-scheduler/src/schedule-driver.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-scheduler/src/schedule-driver.ts)—while sharing the same DO's durability and resource pool. This pattern reduces overhead compared to spawning separate DO instances for each isolated context.

### How is security enforced between different Durable Objects?

Security relies on capability-based isolation where each DO has a unique identifier and storage namespace. Data cannot be accessed without possessing the specific stub or capability reference. The `AuthenticatedApi.getAdminApi()` method in [`packages/workshop-backend/src/admin-settings.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-backend/src/admin-settings.ts) exemplifies this by requiring explicit capability acquisition before allowing access to deployment-wide settings.