What Are Gadgets in Cloudflare OS? Understanding the Sandboxed Process Model

Gadgets in Cloudflare OS are private, sandboxed application instances that run as isolated Durable Objects, providing each user with their own executable copy of software while enforcing strict security boundaries through the Gatekeeper capability layer.

In the cloudflare/cloudflare-os repository, Gadgets replace traditional multi-tenant SaaS architecture by giving every user a dedicated runtime environment. Instead of sharing a single hosted service, each user receives an isolated process that executes application code securely within Cloudflare's edge infrastructure.

Core Architecture and Isolation

Every Gadget operates inside its own Dynamic Worker facet—a specialized Durable Object that enforces network and data isolation by default.

The Gatekeeper Security Model

According to the source code documentation in README.md (lines 52-60), the Gatekeeper acts as the OS's capability-based driver layer. This system explicitly denies Gadgets access to external networks or other users' data unless explicitly granted through capability tokens. The architecture ensures that even if application code is compromised, the blast radius remains confined to the single Durable Object instance.

Blueprint-to-Gadget Lifecycle

Gadgets instantiate from Blueprints—complete source code templates stored in the system. As implemented in README.md (lines 87-92), creating a new Gadget involves:

  1. Allocating a fresh Durable Object ID for the user session
  2. Loading the Blueprint's client-side code into a sandboxed iframe
  3. Initializing the Cap'n Web RPC connection between the kernel and the new instance

This process guarantees that every user starts with a pristine environment isolated from other instances.

API Surface and Communication Protocol

The frontend and backend communicate through a persistent WebSocket connection utilizing Cap'n Web RPC. In /packages/workshop-shared/src/api.ts (lines 3991-3999), the shared GadgetClient interface defines the contract between the UI and the "kernel" backend provided by the workshop-backend package.

// Front‑end: Open a gadget by its ID (React route)
import { useParams } from "react-router-dom";
import { useGadgetClient } from "@gadgets/workshop-frontend/api";

export function GadgetPage() {
  const { id } = useParams();                     // ← gadget UUID from URL
  const gadget = useGadgetClient(id);             // ← RpcStub<GadgetClient>
  
  // Call a method defined by the gadget’s server side
  const doSomething = async () => {
    const result = await gadget.doWork({ foo: "bar" });
    console.log(result);
  };

  return <button onClick={doSomething}>Run</button>;
}

The useGadgetClient hook establishes the RPC stub that proxies calls to the server-side implementation running in the Durable Object.

Extensibility and Export Capabilities

Custom Export Formats

Gadgets can declare server-side export functionality by implementing the optional ExportHandler entrypoint. Defined in /packages/workshop-backend/src/gadget-export.ts (lines 12-20), the GadgetExportEntrypoint interface requires two methods:

// Back‑end: Optional export handler a gadget can provide
export interface GadgetExportEntrypoint<Gadget extends DurableObject = DurableObject>
  extends WorkerEntrypoint {
  /** List the export formats the gadget supports. */
  getExportFormats(gadget: GadgetExportCapability<Gadget>): Promise<GadgetExportFormat[]>;

  /** Produce a server‑side export stream. */
  export(gadget: GadgetExportCapability<Gadget>, id: string): Promise<ReadableStream<Uint8Array>>;
}

This allows Gadgets to generate artifacts like PDFs or HTML snapshots without exposing the underlying storage mechanisms to the client.

Blueprint Administration

Administrators create new application templates through the Overseer service in /packages/workshop-backend/src/overseer.ts. The createBlueprint method registers new Gadget types:

// Creating a blueprint (via the admin API)
await adminApi.createBlueprint({
  title: "My Slides",
  description: "A slide‑deck gadget",
  // the blueprint will contain the full source code; every user gets a new instance
});

Real-Time Collaboration Architecture

Because each Gadget persists state within a Durable Object, Cloudflare OS achieves native real-time collaboration. As noted in README.md (lines 44-48), changes synchronize automatically to all connected participants through the Durable Object's built-in WebSocket coordination—no additional pub/sub infrastructure required.

Summary

  • Gadgets in Cloudflare OS are isolated Durable Object instances that provide private, sandboxed execution environments for each user.
  • Security boundaries are enforced by the Gatekeeper capability layer, which restricts network access and cross-user data visibility.
  • Blueprints serve as templates containing full application source code; instantiating a Blueprint creates a fresh Gadget with pristine state.
  • Cap'n Web RPC provides the communication protocol between the React frontend (workshop-frontend) and the kernel backend (workshop-backend).
  • Export handlers allow Gadgets to implement custom serialization formats through the GadgetExportEntrypoint interface.
  • Multi-user collaboration is inherent to the architecture due to Durable Object state persistence and WebSocket streaming.

Frequently Asked Questions

How do Gadgets in Cloudflare OS differ from traditional serverless functions?

Traditional serverless functions are typically stateless and shared across all users, whereas Gadgets are stateful Durable Objects that maintain isolated persistence for each user session. According to the cloudflare/cloudflare-os source code, every Gadget runs in its own Dynamic Worker facet with dedicated memory and storage, preventing the "noisy neighbor" problems common in multi-tenant SaaS platforms.

What programming interfaces are required to build a custom Gadget?

Developers must implement the GadgetClient interface defined in /packages/workshop-shared/src/api.ts for core functionality, and optionally extend GadgetExportEntrypoint in /packages/workshop-backend/src/gadget-export.ts for custom export capabilities. The frontend consumes these interfaces through the useGadgetClient React hook, while the backend implements them within a Durable Object class.

Can Gadgets communicate with external APIs or databases?

By default, Gadgets cannot access external networks due to the Gatekeeper isolation layer. However, the capability-based security model allows explicit grants for specific resources. The system treats network access as a privileged capability that must be explicitly declared in the Gadget's permissions rather than being available by default to all instantiated Blueprints.

How does Blueprint instantiation ensure user data isolation?

When createBlueprint is called (implemented in packages/workshop-backend/src/overseer.ts), the system allocates a unique Durable Object ID for each user instance. The client code loads into a sandboxed iframe that only connects to that specific Durable Object, ensuring that memory, filesystem, and network contexts remain completely separate between different instantiations of the same Blueprint.

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 →