Cap'n Web: a new RPC system for browsers and web servers

Relationship to Cap’n Proto and design goals

  • Cap’n Web is presented as a simplification of Cap’n Proto RPC, with a much smaller and clearer state machine.
  • Some commenters hope the new design will feed back into Cap’n Proto (for C++, Rust, etc.), but the author notes this would be a large “running-in-place” rewrite.
  • The protocol is schemaless at the wire level but heavily inspired by Cap’n Proto’s object-capability model and promise pipelining.

Object capabilities, promise pipelining, and arrays

  • Core features: pass-by-reference objects and callbacks, bidirectional calls, and promise pipelining so chains of calls incur one network round trip.
  • Over WebSockets, multiple calls are sent without waiting for replies; with HTTP batch, calls are concatenated into one request.
  • Arrays are handled via a special .map() on RpcPromise that “records” the callback once with placeholder promises, then replays on the server as a tiny DSL.
    • This enables server-side fan-out (e.g., per-item lookups) without multiple RTTs.
    • Conditionals, computation, and side effects inside the mapper are largely disallowed or dangerous; several people see this as powerful but “magical” and footgun-prone.

Schemas, typing, and “schemaless” concerns

  • “Schemaless” means the protocol doesn’t know types; schema responsibility is pushed to the application.
  • Many want strong schemas at the RPC boundary; suggestions include TypeScript-only schemas with generated runtime checks, or Zod/Arktype-style validators.
  • Some dislike duplicating definitions (TS + Zod), others note Zod can be the single source of truth.

Comparison with other systems

  • Compared with JSON-RPC: Cap’n Web adds object references, lifecycle management, and pipelining at the cost of more protocol complexity.
  • Compared with GraphQL:
    • Similar “nesting”/shape selection via promise chains and .map(), but lacks built-in solutions for N+1/database batching, query planning, and federation.
    • Several argue GraphQL’s dataloader, query-costing, and federated gateways remain advantages.
  • Compared with OCapN: Cap’n Web lacks sturdyrefs and third-party handoff; positioned more as client–server SaaS than general distributed capability routing.
  • Compared with REST/gRPC: seen as a more natural fit to function-call mental models and object capabilities, but critics warn about repeating CORBA-style “remote looks local” pitfalls.

State, sessions, scaling, and reconnection

  • Each RPC session has import/export tables for capabilities; state is per-connection:
    • WebSocket: lasts for the socket lifetime.
    • HTTP batch: lasts for a single request.
  • Reconnects invalidate old stubs; apps must reconstruct object graphs and subscriptions. Patterns described include re-fetching from a root stub in React.
  • Some worry about server affinity, load balancing with long-lived sockets, and easy DoS via slow/unresponsive clients. Others argue these issues are generic to WebSocket-heavy systems and belong in load balancers/infra.

Security and safety

  • Concerns about untyped inputs, callback stubs, and accidental invocation of remote functions (e.g., via toString/toJSON) are raised.
  • The protocol blocks overriding dangerous prototype methods and recommends runtime type checking; more automated TS-based validation is a stated goal.
  • .map() requires side-effect-free callbacks; misuses (branching, coercion of promises to booleans/strings) can silently behave oddly, so linters or different method names (rpcMap) are suggested.

Language support and portability

  • Today it’s TypeScript/JavaScript only; the design depends heavily on JS dynamism and small bundle size.
  • Dynamic languages like Python are seen as plausible future targets; static languages would likely be better served by Cap’n Proto plus a Cap’n Web–to–Cap’n Proto proxy.
  • Some view TS focus as a strength (no separate IDL); others see lack of cross-language support as a dealbreaker for “real” RPC.

Use cases, enthusiasm, and skepticism

  • Enthusiasts like the uniform model across browser, workers, iframes, and web workers, plus the ability to pass rich capabilities instead of just data.
  • Potential uses include internal APIs, worker–worker communication, and inter-context messaging; some are wary of using it for public APIs without more tooling (dataloaders, rate limiting, query planning).
  • Skeptics worry about:
    • Hiding network boundaries and latency behind “local-looking” calls.
    • The complexity and subtle semantics of pipelining and .map().
    • Tight coupling to TS/JS and difficulty of porting to other stacks.
  • Others argue these abstractions are acceptable when used by teams that understand the distributed semantics and add explicit limits, logging, and patterns on top.