# How Promise Pipelining Works with Cap'n Web RPC in Cloudflare OS

> Learn how promise pipelining in Capn Web RPC for Cloudflare OS resolves values server-side, eliminating client-side awaits for efficient remote procedure calls.

- Repository: [Cloudflare/cloudflare-os](https://github.com/cloudflare/cloudflare-os)
- Tags: deep-dive
- Published: 2026-09-04

---

**Cloudflare OS leverages promise pipelining in Cap'n Web RPC to forward unresolved promises as arguments to subsequent remote procedure calls, allowing the runtime to resolve values server-side before delivery and eliminating redundant client-side await statements.**

The **cloudflare/cloudflare-os** repository implements a capability-based communication architecture between frontend interfaces and backend Workers using **Cap'n Web RPC**. This system utilizes **promise pipelining** to minimize network round trips and simplify asynchronous workflows by treating promises as first-class capabilities that can be used before resolution.

## Understanding Promise Pipelining in Cap'n Web RPC

**Promise pipelining** enables clients to use the return value of an RPC call before the call has actually resolved. When a method returns a stub representing a remote capability, the client can immediately use that stub in subsequent calls without awaiting the resolution.

According to the repository documentation in [`AGENTS.md`](https://github.com/cloudflare/cloudflare-os/blob/main/AGENTS.md), this pattern works because "the promise itself can be used in place of the stub" and "the promise will be replaced with its resolution on the server side before delivering the arguments"【/AGENTS.md#L98-L100】. The Cap'n Web runtime forwards the promise internally and resolves it during the next RPC hop, effectively batching dependent operations into a single network round trip.

## Implementation Patterns in Cloudflare OS

Cloudflare OS applies promise pipelining across multiple frontend components to streamline capability-based workflows and reduce latency.

### Authentication Flow (useAuth.ts)

In [`packages/workshop-frontend/src/useAuth.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-frontend/src/useAuth.ts), the authentication hook attaches a JWT to the request and then uses the returned promise directly instead of awaiting it【/packages/workshop-frontend/src/useAuth.ts#L84-L86】【/packages/workshop-frontend/src/useAuth.ts#L110-L112】.

```typescript
// packages/workshop-frontend/src/useAuth.ts
const authPromise = rpcClient.authenticate(); // Attaches JWT
// Use the promise directly without await – pipelining handles resolution
const result = rpcClient.someSecureMethod(authPromise);

```

### Gadget Management (GadgetList.tsx)

The `GadgetList` component in [`packages/workshop-frontend/src/components/GadgetList.tsx`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/workshop-frontend/src/components/GadgetList.tsx) demonstrates aggressive pipelining when managing gadget instances. The component calls `setPinned` and `setTitle` using the unresolved promise from `openGadget` without intermediate await statements【/packages/workshop-frontend/src/components/GadgetList.tsx#L288-L291】【/packages/workshop-frontend/src/components/GadgetList.tsx#L311-L314】.

```typescript
// packages/workshop-frontend/src/components/GadgetList.tsx
const openPromise = session.openGadget(gadgetId);
// Immediately pipeline the promise to subsequent calls
session.setPinned(openPromise, true);
session.setTitle(openPromise, "New Title");

```

## Capability Lifecycle and Resource Management

While promise pipelining improves performance, pipelined capabilities require explicit cleanup to prevent resource leaks. As documented in [`packages/gatekeeper-google/src/drive-types.d.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-google/src/drive-types.d.ts), returned RPC capabilities support promise pipelining but must be disposed when no longer needed. The [`docs/observers.md`](https://github.com/cloudflare/cloudflare-os/blob/main/docs/observers.md) file further explains that observers must handle pipelined promises correctly when opening resources to avoid race conditions.

The runtime supports `Symbol.dispose` methods or `using` statements for automatic cleanup. Failing to dispose of pipelined stubs can leave dangling references in the Cap'n Web RPC layer, potentially exhausting server-side capability tables.

## Summary

- **Promise pipelining** allows using unresolved RPC promises as arguments to subsequent calls, eliminating intermediate await statements and reducing network latency.
- **Cloudflare OS** implements this pattern in [`useAuth.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/useAuth.ts) and [`GadgetList.tsx`](https://github.com/cloudflare/cloudflare-os/blob/main/GadgetList.tsx) to streamline authentication and gadget management workflows.
- **Server-side resolution** occurs automatically in the Cap'n Web runtime, replacing promises with their resolved stubs before arguments are processed.
- **Capability disposal** is required for pipelined stubs using `stub[Symbol.dispose]()` or `using` statements to prevent memory leaks.

## Frequently Asked Questions

### What is the primary advantage of promise pipelining in Cap'n Web RPC?

Promise pipelining eliminates network round trips by allowing clients to chain dependent RPC calls without waiting for intermediate resolutions. The runtime forwards the promise and resolves it server-side before processing the dependent call, effectively batching what would otherwise be sequential requests.

### How does Cloudflare OS handle promise resolution server-side?

According to the [`AGENTS.md`](https://github.com/cloudflare/cloudflare-os/blob/main/AGENTS.md) documentation, the Cap'n Web RPC runtime automatically replaces pipelined promises with their resolved values on the server side before delivering the arguments to the target method【/AGENTS.md#L98-L100】. This happens transparently to the application code.

### Do pipelined promises require special cleanup?

Yes. Pipelined capabilities returned from RPC calls maintain server-side resources until explicitly released. As noted in [`packages/gatekeeper-google/src/drive-types.d.ts`](https://github.com/cloudflare/cloudflare-os/blob/main/packages/gatekeeper-google/src/drive-types.d.ts), applications should use `stub[Symbol.dispose]()` or `using` statements to ensure proper cleanup of pipelined stubs and prevent capability table exhaustion.

### Can promise pipelining be used with non-capability return values?

Yes. The documentation in [`AGENTS.md`](https://github.com/cloudflare/cloudflare-os/blob/main/AGENTS.md) indicates that Cap'n Web RPC allows using promises for future results even when they are not capability stubs. The runtime will resolve these values server-side before argument delivery, though Cloudflare OS most commonly applies this pattern to capability-based workflows.