How Cloudflare OS Uses Cloudflare Workers: A Modular Full-Stack Architecture
Cloudflare OS is built entirely as a distributed system of Cloudflare Workers, using a Router Worker for traffic distribution, a Workshop Backend Worker for core logic and RPC, isolated Gatekeeper Workers for third-party integrations, and Durable Objects for persistent state management.
Cloudflare OS implements a full-stack "gadget" platform where every architectural layer runs as a Cloudflare Worker. According to the cloudflare/cloudflare-os source code, the system leverages service bindings, Durable Objects, and a custom Cap'n Web RPC protocol to create a modular, secure, and scalable serverless architecture.
Architecture Overview
The platform consists of specialized Workers orchestrated through environment bindings defined in worker-configuration.d.ts files. The Router Worker serves as the public entry point, while the Workshop Backend Worker handles core application logic. Third-party capabilities are isolated in Gatekeeper Workers, and state persists in Durable Objects accessed via RPC stubs.
The Router Worker: Traffic Distribution
Located at packages/router/src/index.ts, the Router Worker handles all incoming HTTP traffic and dispatches requests using service bindings. It dynamically discovers Gatekeeper Workers by scanning environment variables prefixed with GATEKEEPER_, normalizing the suffix to URL-friendly paths.
Dynamic Gatekeeper Discovery
The Router inspects req.url and forwards requests to the appropriate backend service. For paths starting with /gatekeeper/<name>, it routes to the corresponding service binding. API and blueprint paths route to the Workshop Backend.
// packages/router/src/index.ts
for (const key of Object.keys(env)) {
if (!key.startsWith("GATEKEEPER_")) continue;
const suffix = key.slice("GATEKEEPER_".length).toLowerCase().replaceAll("_", "-");
const prefix = `/gatekeeper/${suffix}`;
if (url.pathname === prefix || url.pathname.startsWith(prefix + "/")) {
// Forward the request to the gatekeeper service binding.
return (env[key] as Fetcher).fetch(req);
}
}
In development, when no ASSETS binding exists, the Router also proxies frontend requests to the backend for local testing.
The Workshop Backend: Core Application Logic
The Workshop Backend Worker (packages/workshop-backend/src/server.ts) implements authentication, user management, gadget lifecycle operations, and analytics. It exposes a single /api endpoint that creates RPC sessions.
RPC Over HTTP and WebSocket
The backend uses Cap'n Web RPC to provide low-overhead, promise-pipelined communication. It supports both HTTP-batch and WebSocket transports, with the latter enabling persistent connections for real-time gadget interactions.
// packages/workshop-backend/src/server.ts
return await newWorkersRpcResponse(
req,
new PublicApiImpl(ctx, env, abortSession, accessPayload),
{ abortSignal: abortController.signal } // aborts the WS when the session ends
);
For WebSocket upgrades, the backend returns socket pairs and initializes newWebSocketRpcSession to maintain the connection.
Durable Objects for State Management
State persists in Durable Objects like UserDurableObject and OverseerDurableObject (defined in packages/workshop-backend/src/overseer.ts). The backend creates unique IDs via env.<DO_NAMESPACE>.newUniqueId() and wraps stubs with telemetry.
// packages/workshop-backend/src/server.ts (inside AuthenticatedApiImpl)
private get #user(): DurableObjectStub<UserDurableObject> {
// Wrap the stub to add telemetry.
return wrapDoStubForTelemetry(this.users.get(this.#userId));
}
The OverseerDurableObject represents workspaces and mediates gadget execution, while UserDurableObject maintains user-specific state.
Gatekeeper Workers: Isolated Third-Party Integrations
Gatekeepers are separate Workers (e.g., packages/gatekeeper-zoominfo/src/zoominfo.ts) bound to the Router via GATEKEEPER_<NAME> service bindings. Each encapsulates specific external capabilities like OAuth flows or data APIs, running in isolation from the core platform.
When a gadget requires third-party access, the backend creates a gatekeeper stub through overseerResult.newGatekeeper and returns it to the client, which then communicates directly with the isolated Worker.
Environment Configuration and Bindings
Workers obtain configuration, KV stores, R2 buckets, and inter-service references through typed Env interfaces. These are declared in each package's worker-configuration.d.ts (e.g., packages/router/worker-configuration.d.ts) and accessed via the env argument in fetch handlers.
The shared type-only package @gadgets/workshop-shared/api (located in packages/workshop-shared/src/api.ts) defines the RPC interfaces (PublicApi, AuthenticatedApi, AdminApi) used across the system, with automatic validation via @validateRpc decorators.
Summary
- Router Worker (
packages/router/src/index.ts) serves as the public entry point, dynamically routing traffic to Gatekeeper Workers or the Workshop Backend based on URL patterns andGATEKEEPER_*service bindings. - Workshop Backend (
packages/workshop-backend/src/server.ts) implements core logic using Cap'n Web RPC over HTTP and WebSocket, handling authentication and gadget lifecycle management. - Durable Objects (
UserDurableObject,OverseerDurableObject) provide persistent state storage, accessed via RPC stubs wrapped with telemetry utilities. - Gatekeeper Workers run as isolated Cloudflare Workers for third-party integrations, discovered automatically by the Router through environment variable scanning.
- The platform uses Cap'n Web RPC for efficient, type-safe communication between clients and backend services.
Frequently Asked Questions
How does the Router Worker distribute traffic in Cloudflare OS?
The Router Worker inspects the req.url pathname and forwards requests based on routing rules. Paths matching /gatekeeper/<name> are forwarded to the corresponding GATEKEEPER_* service binding, while API routes go to the WORKSHOP_BACKEND binding. Static assets are served from the ASSETS binding in production.
What role do Durable Objects play in Cloudflare OS?
Durable Objects like UserDurableObject and OverseerDurableObject persist user state, workspace state, and gatekeeper account information. They are instantiated using env.<DO_NAMESPACE>.get(id) and accessed via RPC stubs that automatically handle serialization and telemetry wrapping.
How does Cloudflare OS handle real-time communication between clients and gadgets?
The platform uses Cap'n Web RPC with WebSocket upgrades. When a client connects, the Workshop Backend creates a WebSocket RPC session via newWebSocketRpcSession, providing a persistent channel for promise-pipelined RPC calls that remains active until the session ends.
How are third-party integrations secured and isolated?
Third-party capabilities are encapsulated in Gatekeeper Workers—separate Cloudflare Workers that run in isolation and communicate only through defined service bindings. Each Gatekeeper handles its own OAuth flows and API interactions (e.g., packages/gatekeeper-zoominfo/src/zoominfo.ts), preventing external dependencies from affecting core platform stability.
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 →