---
title: xxRPC
description: Design portable xxRPC contracts that keep application semantics in Protobuf.
---

# How xxRPC is meant to be used

xxRPC connects programs written in different languages through a shared Protobuf schema. The schema owns the complete application contract: service names, procedure names, request data, response data, and expected errors.

HTTP and WebSocket carry xxRPC messages. They do not define the application contract. Application code must not depend on untyped HTTP headers, cookies, status codes, or other transport details that are absent from the Protobuf schema.

This separation lets the same service support browsers, command-line tools, backend programs, and other clients without changing its contract for one environment.

## The Protobuf schema owns the contract

If a value can change what a procedure does, put that value in the schema. Examples include:

- authentication credentials;
- an organization or tenant identifier;
- pagination cursors;
- idempotency keys;
- feature-specific options;
- successful results;
- expected errors.

Do not pass these values through custom HTTP headers. A header is not part of a generated procedure type, so a caller can omit it while still satisfying the apparent contract. The server can also start depending on a header without causing clients in other languages to fail at compile time.

xxRPC uses transport metadata internally to route and deliver calls. Generated clients and handlers own that metadata. Application code must not use transport metadata as an undeclared extension to a procedure.

Server resources do not belong in the schema. Databases, secrets, loggers, and platform bindings are implementation dependencies. Pass them to the handler implementation through constructors or other internal module interfaces.

## Errors are procedure results

Expected errors are part of a procedure's response schema. Model success and error cases with a Protobuf `oneof`:

```proto
service Tasks {
  rpc CreateTask(CreateTaskRequest) returns (CreateTaskResponse);
}

message CreateTaskRequest {
  string access_token = 1;
  string organization_id = 2;
  string title = 3;
}

message CreateTaskResponse {
  oneof result {
    Task task = 1;
    CreateTaskError error = 2;
  }
}

message CreateTaskError {
  oneof kind {
    Unauthenticated unauthenticated = 1;
    PermissionDenied permission_denied = 2;
    OrganizationNotFound organization_not_found = 3;
    InvalidTask invalid_task = 4;
  }
}
```

The handler returns a `CreateTaskResponse` for each expected outcome. It does not throw an exception for invalid credentials, denied access, missing data, conflicts, or business-rule failures. Generated clients receive a typed response and must handle its result variant.

Protobuf permits a `oneof` to be unset. Handlers must set every result and error `oneof`. Clients must treat an unset `oneof` as a contract violation, not as another application outcome.

Use exceptions only when the implementation cannot produce a valid contract response. Examples include a programming error or a failure to encode the response. Such failures mean that the server did not honor the procedure contract.

For streaming procedures, put expected errors in the stream's message schema. Reserve xxRPC protocol errors for failures that prevent the call from producing its declared messages.

## HTTP only transports the call

An HTTP response status describes whether HTTP and xxRPC delivered a valid procedure answer. It does not describe whether the requested business operation succeeded.

Use these semantics:

| Situation                                            | HTTP status | Response                                     |
| ---------------------------------------------------- | ----------: | -------------------------------------------- |
| The server cannot identify the service or procedure. |       `404` | No procedure answer exists.                  |
| The request body is not valid Protobuf.              |       `400` | The procedure could not receive its request. |
| The request exceeds the protocol limit.              |       `413` | The procedure could not receive its request. |
| The procedure returns a success variant.             |       `200` | A valid schema-defined answer.               |
| The procedure returns an error variant.              |       `200` | A valid schema-defined answer.               |
| The implementation cannot produce a valid answer.    |       `500` | The procedure contract was not honored.      |

A semantically invalid value is still a decoded request. For example, an empty title or an expired credential must produce a schema-defined error with HTTP `200`. HTTP `400` is for a message that xxRPC cannot deliver to the procedure as a valid Protobuf request.

Do not map application errors to HTTP status codes. An HTTP `403`, `404`, or `409` cannot describe a procedure's declared error variants across every xxRPC transport and language.

## Browsers are one kind of client

xxRPC supports browsers through standard browser HTTP and WebSocket facilities. Browser support does not make xxRPC a browser framework.

Cookies are useful for browser-specific authentication, but most xxRPC clients do not have a browser cookie jar. An xxRPC procedure must therefore not require an ambient cookie. Put the RPC credential in the schema. Keep operations that depend on an `HttpOnly` cookie in a separate browser-specific HTTP interface.

The same rule applies to HTTP-specific behavior such as redirects, form submissions, and cache controls. Keep that behavior in an HTTP endpoint unless it belongs in the cross-language RPC contract.

Standard gRPC does not run directly in browsers without another protocol or proxy such as gRPC-Web. tRPC gives TypeScript applications a good in-language experience, but its contract is not a practical shared interface for clients written in other languages. OpenAPI generation does not turn tRPC's TypeScript types and runtime behavior into one authoritative cross-language contract.

xxRPC takes a narrower approach. Protobuf defines the contract once. xxRPC generates clients and handlers for the supported languages and carries those messages over HTTP or WebSocket.

## Not every operation is RPC

Use regular HTTP when HTTP itself provides the useful semantics or when an operation does not fit a procedure message. Common examples include:

- file uploads and downloads;
- static assets;
- webhooks;
- redirects;
- range requests;
- cacheable resources.

A profile picture upload is an HTTP upload endpoint, not an RPC procedure with a hidden raw request body. The upload can return an identifier that later RPC calls use through their schemas.

Using both HTTP endpoints and xxRPC in one application is expected. Keep their interfaces separate. An HTTP endpoint can use headers, cookies, status codes, and streaming body semantics because those details are its declared interface. An xxRPC procedure uses only its Protobuf contract and xxRPC protocol behavior.

## Design checklist

Before adding or changing an xxRPC procedure, check the following rules:

- The Protobuf request contains every caller-provided value that changes procedure behavior.
- The Protobuf response contains every expected success and error outcome.
- The handler returns expected errors instead of throwing them.
- Application behavior does not depend on custom HTTP headers or cookies.
- Server resources enter through implementation dependencies, not request metadata.
- A browser, command-line tool, or backend client can use the same contract.
- Operations that depend on HTTP semantics remain regular HTTP endpoints.

If a generated client can satisfy the procedure type while omitting information that the server requires, the schema is incomplete.

<!--
Sitemap

URL: https://withxx.dev/index.md
Title: xx
Description: Practical, reproducible builds without build-system ceremony

URL: https://withxx.dev/examples/commands.md
Title: Command Examples
Description: General command, environment, and entrypoint patterns.

URL: https://withxx.dev/examples/go.md
Title: Go Examples
Description: Common Go build patterns with managed SDKs.

URL: https://withxx.dev/examples/nodejs.md
Title: Node.js Examples
Description: Common Node.js task patterns with a managed distribution.

URL: https://withxx.dev/examples/zig.md
Title: Zig Examples
Description: Direct Zig commands and Go CGO builds with a managed Zig distribution.

URL: https://withxx.dev/load.md
Title: Loading Files
Description: Split xx configuration into local Starlark modules.

URL: https://withxx.dev/lsp.md
Title: Editor Support
Description: Configure an editor to use xx's built-in Starlark language server.

URL: https://withxx.dev/packages/cloudflare/cf_d1_create.md
Title: cf_d1_create
Description: Provision a Cloudflare D1 database with Wrangler.

URL: https://withxx.dev/packages/cloudflare/cf_kv_create.md
Title: cf_kv_create
Description: Provision a Cloudflare Workers KV namespace with Wrangler.

URL: https://withxx.dev/packages/cloudflare/cf_queue_create.md
Title: cf_queue_create
Description: Provision and configure a Cloudflare Queue with Wrangler.

URL: https://withxx.dev/packages/cloudflare/cf_r2_create.md
Title: cf_r2_create
Description: Provision and configure a Cloudflare R2 bucket with Wrangler.

URL: https://withxx.dev/packages/cloudflare/cf_worker_config.md
Title: cf_worker_config
Description: Define an in-memory Cloudflare Worker configuration.

URL: https://withxx.dev/packages/cloudflare/cf_wrangler_deploy.md
Title: cf_wrangler_deploy
Description: Deploy a Cloudflare Worker with a temporary Wrangler configuration.

URL: https://withxx.dev/packages/cloudflare/cf_wrangler_dev.md
Title: cf_wrangler_dev
Description: Run one or more Cloudflare Workers with Wrangler dev.

URL: https://withxx.dev/packages/cmake/cmake.md
Title: cmake
Description: Activate managed CMake for dependent tasks.

URL: https://withxx.dev/packages/cmake/cmake_build.md
Title: cmake_build
Description: Build a generated project with managed CMake.

URL: https://withxx.dev/packages/cmake/cmake_generate.md
Title: cmake_generate
Description: Generate a project build system with managed CMake.

URL: https://withxx.dev/packages/doppler/doppler_secrets.md
Title: doppler_secrets
Description: Load Doppler secrets into dependent task environments.

URL: https://withxx.dev/packages/git/git_clone.md
Title: git_clone
Description: Materialize a pinned Git source tree with host Git configuration and access.

URL: https://withxx.dev/packages/git/git_commit.md
Title: git_commit
Description: Stage and commit changes in a Git repository.

URL: https://withxx.dev/packages/git/git_init_repository.md
Title: git_init_repository
Description: Ensure an empty SHA-1 or SHA-256 Git repository exists.

URL: https://withxx.dev/packages/git/git_push.md
Title: git_push
Description: Push commits from a Git repository.

URL: https://withxx.dev/packages/git/git_semver_latest.md
Title: git_semver_latest
Description: Read the latest semantic version from local Git tags.

URL: https://withxx.dev/packages/git/git_semver_next.md
Title: git_semver_next
Description: Calculate the next semantic version from local Conventional Commits.

URL: https://withxx.dev/packages/git/git_sha.md
Title: git_sha
Description: Resolve a local Git revision to its commit ID.

URL: https://withxx.dev/packages/git/git_tag.md
Title: git_tag
Description: Create a lightweight or annotated Git tag.

URL: https://withxx.dev/packages/go/go.md
Title: go
Description: Activate a managed Go SDK for dependent tasks.

URL: https://withxx.dev/packages/go/go_binary.md
Title: go_binary
Description: Build a Go command with a managed SDK.

URL: https://withxx.dev/packages/go/go_install.md
Title: go_install
Description: Install a versioned Go command for dependent tasks.

URL: https://withxx.dev/packages/go/go_protobuf.md
Title: go_protobuf
Description: Install protoc-gen-go and provide it as a Protobuf generator.

URL: https://withxx.dev/packages/go/go_run.md
Title: go_run
Description: Run a local program or versioned Go command with a managed SDK.

URL: https://withxx.dev/packages/go/go_test.md
Title: go_test
Description: Test Go packages with a managed SDK.

URL: https://withxx.dev/packages/http/http_proxy.md
Title: http_proxy
Description: Route local HTTP and WebSocket traffic between development servers.

URL: https://withxx.dev/packages/io/io_append_text.md
Title: io_append_text
Description: Append text to a file asynchronously.

URL: https://withxx.dev/packages/io/io_copy.md
Title: io_copy
Description: Copy a file or directory asynchronously.

URL: https://withxx.dev/packages/io/io_glob.md
Title: io_glob
Description: Find project files and directories with recursive glob patterns.

URL: https://withxx.dev/packages/io/io_read_text.md
Title: io_read_text
Description: Read a text file during build evaluation.

URL: https://withxx.dev/packages/io/io_rm.md
Title: io_rm
Description: Remove a file asynchronously.

URL: https://withxx.dev/packages/io/io_rmdir.md
Title: io_rmdir
Description: Remove a directory tree asynchronously.

URL: https://withxx.dev/packages/io/io_stat.md
Title: io_stat
Description: Read file information during build evaluation.

URL: https://withxx.dev/packages/io/io_write_text.md
Title: io_write_text
Description: Write text to a file asynchronously.

URL: https://withxx.dev/packages/ninja/ninja.md
Title: ninja
Description: Activate managed Ninja for dependent tasks.

URL: https://withxx.dev/packages/nodejs/nodejs.md
Title: nodejs
Description: Activate managed Node.js for dependent tasks.

URL: https://withxx.dev/packages/nodejs/npm_install.md
Title: npm_install
Description: Install dependencies with the package.json-selected manager.

URL: https://withxx.dev/packages/nodejs/npm_run.md
Title: npm_run
Description: Run a project package script with the package.json-selected manager.

URL: https://withxx.dev/packages/nodejs/npx_run.md
Title: npx_run
Description: Run a versioned npm package command with managed npx.

URL: https://withxx.dev/packages/os/env_append.md
Title: env_append
Description: Append an item to a list-like environment variable.

URL: https://withxx.dev/packages/os/env_get.md
Title: env_get
Description: Read a value from a task environment while evaluating Starlark.

URL: https://withxx.dev/packages/os/env_prepend.md
Title: env_prepend
Description: Prepend an item to a list-like environment variable.

URL: https://withxx.dev/packages/os/env_set.md
Title: env_set
Description: Set an environment variable for dependent tasks.

URL: https://withxx.dev/packages/os/env_unset.md
Title: env_unset
Description: Remove an environment variable from dependent tasks.

URL: https://withxx.dev/packages/os/os_arch.md
Title: os_arch
Description: Identify the host processor architecture.

URL: https://withxx.dev/packages/os/os_kernel.md
Title: os_kernel
Description: Identify the host operating system kernel.

URL: https://withxx.dev/packages/os/os_msvc.md
Title: os_msvc
Description: Activate the host Microsoft Visual C++ tools.

URL: https://withxx.dev/packages/os/os_run.md
Title: os_run
Description: Run a command from a project directory.

URL: https://withxx.dev/packages/os/os_system_tools.md
Title: os_system_tools
Description: Activate standard host operating-system utilities.

URL: https://withxx.dev/packages/os/os_xcode.md
Title: os_xcode
Description: Activate the host Xcode tools.

URL: https://withxx.dev/packages/os/path_make_absolute.md
Title: path_make_absolute
Description: Resolve a relative path from the project root.

URL: https://withxx.dev/packages/protobuf/protobuf_generate.md
Title: protobuf_generate
Description: Generate source code with a managed Protobuf compiler.

URL: https://withxx.dev/packages/protobuf/protobuf_generator.md
Title: protobuf_generator
Description: Adapt an installed protoc plugin dependency for code generation.

URL: https://withxx.dev/packages/protobuf/protoc.md
Title: protoc
Description: Activate a managed Protobuf compiler for dependent tasks.

URL: https://withxx.dev/packages/secrets/xx_secrets.md
Title: xx_secrets
Description: Load xx project secrets into dependent task environments.

URL: https://withxx.dev/packages/stripe/stripe.md
Title: stripe
Description: Activate a managed Stripe CLI for dependent tasks.

URL: https://withxx.dev/packages/stripe/stripe_listen.md
Title: stripe_listen
Description: Forward Stripe webhook events to a local endpoint.

URL: https://withxx.dev/packages/text/text_template.md
Title: text_template
Description: Render Go text templates from Starlark data and functions.

URL: https://withxx.dev/packages/xxrpc/xxrpc_client.md
Title: xxrpc_client
Description: Generate typed HTTP and WebSocket RPC clients for ECMAScript or Go.

URL: https://withxx.dev/packages/xxrpc/xxrpc_handler.md
Title: xxrpc_handler
Description: Generate typed framework-neutral ECMAScript RPC handler classes.

URL: https://withxx.dev/packages/zig/zig.md
Title: zig
Description: Activate managed Zig for dependent tasks.

URL: https://withxx.dev/packages/zig/zig_cc.md
Title: zig_cc
Description: Configure managed Zig as a C and C++ compiler.

URL: https://withxx.dev/packages.md
Title: Built-in Packages
Description: Versioned toolchains, commands, and task environment helpers provided by xx.

URL: https://withxx.dev/secrets.md
Title: Secret manager
Description: Store project secrets locally and provide them to xx tasks.

URL: https://withxx.dev/xxrpc.md
Title: xxRPC
Description: Design portable xxRPC contracts that keep application semantics in Protobuf.
-->
