oRPC: OpenAPI Remote Procedure Call for Type-Safe APIs
oRPC (OpenAPI Remote Procedure Call) combines the familiarity of RPC with the industry-standard OpenAPI spec so that every request/response is fully typed from client to server. 
Every seasoned engineer knows the real break-points in a system aren’t inside the algorithms—they’re in the seams where services talk.
Schema drift sneaks in during a late-night hot-fix, a version bump lands without regeneration, and suddenly the JSON your mobile team committed to memory is 2 fields off. You patch, you document, somebody forgets—repeat.
oRPC ends that loop by collapsing “definition,” “implementation,” and “documentation” into a single, type-safe contract that travels unchanged from server to edge to browser. Think RPC ergonomics, OpenAPI guarantees, and zero code-gen. If keeping micro-services honest feels like half your sprint, read on.

Why another API toolkit?
End-to-end type-safety
Types flow from server procedure → wire → client with no manual sync or code generation, eliminating an entire class of integration bugs.
Contract-first or code-first
Start with plain TypeScript, or author an OpenAPI contract and let oRPC enforce it—either way, your source of truth lives in one place.
Minimal boilerplate, maximal DX
Define procedures like ordinary functions; forget repetitive route maps and hand-rolled serializers.
Multi-runtime portability
Run the same router on Node, Bun, Deno, Cloudflare Workers, or the browser without touching a line of business logic.
MIT-licensed & community-driven
Development happens in the open at unnoq/orpc—no vendor lock-in, permissive license, and a fast-growing plugin ecosystem.
Getting started
Install the core packages
npm i @orpc/server @orpc/client
Define a tiny “hello” router
// hello.ts
import { os } from '@orpc/server';
import { z } from 'zod';
export const hello = os
.input(z.string()) // expect a single string
.handler(({ input }) => `Hello, ${input}!`);
export const router = { hello };
Spin up a server (Node example)
// server.ts
import { createServer } from 'node:http';
import { RPCHandler } from '@orpc/server/node';
import { router } from './hello';
const handler = new RPCHandler(router);
createServer((req, res) => handler.handle(req, res))
.listen(3000, () => console.log('oRPC listening on :3000'));
Call it from any TS/JS runtime
// client.ts
import { createORPCClient } from '@orpc/client';
import { RPCLink } from '@orpc/client/fetch';
import type { RouterClient } from '@orpc/server';
import { router } from './hello'; // shared types
const orpc: RouterClient<typeof router> = createORPCClient(
new RPCLink({ url: 'http://localhost:3000' })
);
console.log(await orpc.hello('Alice')); // → "Hello, Alice!"
How it works
Patterns you’ll actually ship
Error handling
import { ORPCError } from '@orpc/server';
export const divide = os
.input(z.object({ a: z.number(), b: z.number().nonzero() }))
.handler(({ input: { a, b } }) => a / b);
On the client:
try {
await orpc.divide({ a: 10, b: 0 });
} catch (e) {
if (e instanceof ORPCError && e.code === 'BAD_REQUEST') {
/* graceful UI message */
}
}
Auth middleware
import { ORPCError } from '@orpc/server';
const withAuth = os.$context<{ user?: User }>().use(({ context, next }) => {
const user = verifyJwt(context.headers?.authorization);
if (!user) throw new ORPCError('UNAUTHORIZED');
return next({ context: { user } });
});
Compose withAuth into any procedure to protect it.
When to reach for oRPC
Micro-frontends & BFFs
Multiple UIs can share a single contract, guaranteeing that every feature team ships against the same typed boundary.
Server Actions on the Edge
A single .actionable() call turns any procedure into a React/Next 15 server action, complete with streamed payloads and manifest hydration.
Edge-first workloads
Deploy unchanged handlers to Cloudflare Workers, Deno Deploy, or Bun servers—latency stays low, and the contract remains intact.
Teams that care about OpenAPI
oRPC emits a full spec on demand, so your Swagger UI and Postman collections are always in sync with running code.
Final thoughts
If you’re tired of duplicating types between front-end and back-end—or bolting OpenAPI on after the fact—oRPC lets you write a function and automatically get a fully typed, OpenAPI-compliant endpoint.