This article introduces Cap'n Web, a new Remote Procedure Call (RPC) system implemented in pure TypeScript, designed for modern web environments. Building on the object-capability principles of its predecessor Cap'n Proto, Cap'n Web distinguishes itself with zero boilerplate, human-readable JSON serialization, and broad compatibility across browsers, Cloudflare Workers, and Node.js. It supports advanced features like bidirectional calling, passing functions and objects by reference, and promise pipelining, which enables chaining multiple RPCs into a single network round trip to mitigate latency. Cap'n Web facilitates natural, JavaScript-like API design, integrates seamlessly with TypeScript for end-to-end type safety, and offers a compelling alternative to GraphQL for solving data-fetching "waterfall" problems with greater composability. It also introduces an innovative server-side array mapping feature to optimize list processing. Currently experimental but already used in Cloudflare's remote bindings for Wrangler, Cap'n Web is an open-source solution for efficient and secure inter-application communication.
Cap'n Web: A New RPC System for Browsers and Web Servers
[Introduction to Cap'n Web] A Web-Native RPC System: Cap'n Web is a new RPC protocol and TypeScript implementation, a "spiritual sibling" to Cap'n Proto, specifically designed for the web stack.
[Core Distinctions from Cap'n Proto] Simplified and Web-Friendly: Unlike Cap'n Proto, it has no schemas or boilerplate, uses human-readable JSON serialization (with pre/post-processing for special types), and works over HTTP, WebSocket, and postMessage() out-of-the-box.
[Broad Compatibility & Small Footprint] Universal JavaScript Support: It operates in all major browsers, Cloudflare Workers, Node.js, and other modern JavaScript runtimes, compressing to under 10 kB (minify+gzip) with no dependencies, and is open source under the MIT license.
[Object-Capability Model Explained] Expressive and Powerful: Cap'n Web implements an object-capability RPC model, allowing:
Bidirectional Calling: Both client and server can call each other.
Function/Object References: Functions or RpcTarget-extended objects passed over RPC become "stubs" that invoke calls back to their origin.
Promise Pipelining: Dependent RPCs can be chained in a single network round trip, using a Promise-like Proxy object for speculative method calls.
Capability-Based Security: Enables secure patterns where access to operations is granted by possessing a specific object, making "forging" impossible.
[Trivial Setup] Easy to Implement: Setting up a client involves a single line to create a session (e.g., newWebSocketRpcSession), and a Cloudflare Worker server is equally straightforward using RpcTarget and newWorkersRpcResponse.
[Why RPC Today?] Modern Relevance: RPC, now with Promises and async/await, overcomes past "fallacies of distributed computing" by making network communication feel like local function calls, streamlining API design and development.
[When to Use] Ideal Use Cases: Best suited for JavaScript applications communicating over a network (client-to-server, microservice-to-microservice), interactive web applications with real-time collaboration, and scenarios with complex security boundaries.
[HTTP Batch Mode] Lightweight Single-Request Calls: Supports making multiple RPCs in a single HTTP request (e.g., newHttpBatchRpcSession), completing the batch once any promise is awaited.
[Chained Calls / Promise Pipelining] Latency Reduction: Enables calls where the input depends on the promise of a previous call's result, executing the entire chain in one network round trip. This is achieved by using JavaScript Proxy objects for returned promises.
[Security Example] Natural Authentication: An authenticate() method can return a secure AuthenticatedSession object, on which further authorized calls can be made. This cleanly integrates authorization into the RPC abstraction, making it type-safe and preventing accidental unauthenticated calls.
[TypeScript Integration] End-to-End Type Safety: Developers can define RPC APIs using TypeScript interfaces, apply them to both client and server, and benefit from type checking and auto-completion. Runtime type validation is not provided by Cap'n Web itself, recommending tools like Zod.
[Alternative to GraphQL] Flattening Waterfalls with JavaScript: Cap'n Web addresses the "waterfall" problem (sequential data fetching) similarly to GraphQL but without introducing new languages or tooling. Its promise pipelining allows complex chained operations and mutations naturally within JavaScript.
[Innovative Array Mapping] Server-Side List Processing: Introduces a special .map() function for promises of arrays, allowing server-side transformations on list elements without additional network round trips. This is achieved through a "record-replay" mechanism, where client-side speculative calls are recorded as instructions for the server.
[Implementation Details] JSON-Based Protocol: Utilizes JSON for serialization, encoding special types (like Date) and literal arrays using "escape sequences" (e.g., ["date", timestamp]). The symmetric RPC protocol involves "export" and "import" tables, unique integer IDs, and "push" (method invocation) and "pull" (result request) messages to facilitate promise pipelining.
[Current Status & Future] Experimental but in Use: Cap'n Web is new and experimental but already forms the basis for Cloudflare's "remote bindings" feature in Wrangler, allowing workerd to communicate with production services. It is open source and available for immediate use.