<!-- StarterPick AI-readable guide source -->
<!-- Canonical: https://starterpick.com/guides/trpc-v11-vs-orpc-vs-ts-rest-type-safe-rpc-saas-boilerplates-2026 -->
<!-- Raw Markdown: https://starterpick.com/guides/trpc-v11-vs-orpc-vs-ts-rest-type-safe-rpc-saas-boilerplates-2026/raw.md -->
<!-- Source path: content/guides/trpc-v11-vs-orpc-vs-ts-rest-type-safe-rpc-saas-boilerplates-2026.mdx -->

---
title: "tRPC v11 vs oRPC vs ts-rest: Type-Safe RPC for SaaS Boilerplates 2026"
description: "tRPC v11, oRPC, and ts-rest compared for SaaS type-safe APIs: programming model, OpenAPI, edge support, and team fit."
date: "2026-04-26"
tier: 2
authors: ["team"]
tags: ["trpc", "orpc", "ts-rest", "type-safe-api", "saas-boilerplate", "2026"]
---

## Quick Verdict

For a TypeScript SaaS boilerplate in 2026:

- **tRPC v11** — the incumbent. Most boilerplate adoption, biggest ecosystem, deepest TanStack Query integration. Default for monorepo full-stack TS apps where the client is your own.
- **oRPC** — newer, OpenAPI-first, contract-first, runs everywhere. Best when you need both end-to-end TS types **and** an OpenAPI surface for third parties.
- **ts-rest** — contract-first, REST-shaped, the "we're shipping HTTP endpoints anyway, just make them typed" choice. Cleanest interop with non-TS clients.

If your boilerplate is "Next.js client + Next.js API routes + your own React components," tRPC is still the answer. If you'll publish a public API or consume from non-TS clients, oRPC or ts-rest.

## Key Takeaways

- All three give end-to-end TypeScript types between server and client.
- tRPC is procedure-first (think RPC). oRPC and ts-rest are contract-first (define the shape, generate the client).
- OpenAPI / public-API support is **first-class in oRPC and ts-rest**, **add-on in tRPC**.
- Server Actions in Next.js 15+ are *not* a replacement for these — see the section below.

## Decision Table

| Scenario | Pick |
|----------|------|
| Greenfield Next.js SaaS, TS client, no public API | **tRPC v11** |
| You'll ship a public REST API to third-party developers | **oRPC** or **ts-rest** |
| Mobile app + web app + maybe Python clients | **oRPC** (OpenAPI generation) |
| Microservices written in TS that need typed contracts | **ts-rest** |
| You like the contract-first style of OpenAPI / FastAPI | **oRPC** |
| Tiny project, Server Actions cover it | Just use Server Actions |

## What "Type-Safe RPC" Solves

The thing none of these is: a swagger generator.
The thing all three are: a way to share *types* between your server endpoints and your client calls so that:

- Renaming a field on the server breaks the client at compile time.
- Removing a parameter breaks the call site immediately.
- Auto-completion on the client knows your endpoint signatures without code generation.

The trade vs. plain HTTP: an extra dependency, slightly more setup, sometimes a build tool involved. The payoff: no `any` between client and server, fewer 500s in production from missing fields.

## tRPC v11

**Pricing:** Free, MIT.

**Fit:** Default for [T3-style boilerplates](/guides/t3-stack-2026), Makerkit, Supastarter, and any premium Next.js boilerplate that bundles a typed client. Designed for monorepos where the client and server are in the same TS codebase.

```ts
// server/routers/post.ts
import { z } from 'zod';
import { publicProcedure, router } from '../trpc';

export const postRouter = router({
  byId: publicProcedure
    .input(z.object({ id: z.string() }))
    .query(({ input }) => db.post.findUnique({ where: { id: input.id } })),
  create: publicProcedure
    .input(z.object({ title: z.string(), body: z.string() }))
    .mutation(({ input }) => db.post.create({ data: input })),
});
```

```tsx
// client
const post = trpc.post.byId.useQuery({ id: 'abc' });
trpc.post.create.useMutation();
```

What you get:

- Tightest TanStack Query integration in the space — `useQuery`, `useMutation`, `useSuspenseQuery`.
- Subscriptions over WebSocket / SSE.
- Middleware for auth, logging, rate limiting.
- Integrations with Next.js, Astro, Express, Fastify, Hono, Bun, Cloudflare Workers.
- v11 added stable streaming responses, better edge support, and stricter type inference.

Where it bites:

- Procedure-first means OpenAPI is an add-on (`trpc-openapi`-style). Public APIs feel grafted-on.
- The client must be TypeScript. No mobile SDKs in non-TS languages without code generation tooling.
- Larger TypeScript build times in big routers.

## oRPC

**Pricing:** Free, MIT.

**Fit:** Boilerplates that need *both* end-to-end TS types and an OpenAPI surface — think B2B SaaS that ships an internal app and a public REST API.

```ts
// contract.ts
import { os } from '@orpc/server';
import { z } from 'zod';

export const router = {
  post: {
    byId: os
      .input(z.object({ id: z.string() }))
      .output(z.object({ id: z.string(), title: z.string() }))
      .handler(({ input }) => db.post.findUnique({ where: { id: input.id } })),
  },
};
```

```ts
// client
import { createORPCClient } from '@orpc/client';
import { OpenAPILink } from '@orpc/openapi-client';

const client = createORPCClient<typeof router>(
  new OpenAPILink({ url: '/api' }),
);
const post = await client.post.byId({ id: 'abc' });
```

What you get:

- Contract is the source of truth — server handler and client call sites both type-check against it.
- Built-in OpenAPI document generation.
- Multi-runtime: Node, Bun, Deno, Edge, Cloudflare Workers, Lambda.
- React / Vue / Solid / Svelte adapters with TanStack Query bindings.
- Streaming responses, file uploads, SSE first-class.

Where it bites:

- Newer ecosystem, fewer Stack Overflow answers than tRPC.
- More opinionated about output types — you can't lazily skip output schemas.

## ts-rest

**Pricing:** Free, MIT.

**Fit:** "We're going to ship REST anyway; let's just make it typed." Microservices, internal APIs that other teams consume, projects where Postman / curl still matter.

```ts
import { initContract } from '@ts-rest/core';
import { z } from 'zod';

const c = initContract();
export const contract = c.router({
  getPost: {
    method: 'GET',
    path: '/posts/:id',
    pathParams: z.object({ id: z.string() }),
    responses: { 200: z.object({ id: z.string(), title: z.string() }) },
  },
});
```

```ts
// server (Express)
import { initServer } from '@ts-rest/express';

const server = initServer();
const router = server.router(contract, {
  getPost: async ({ params }) => ({
    status: 200,
    body: await db.post.findUnique({ where: { id: params.id } }),
  }),
});
```

```ts
// client
import { initClient } from '@ts-rest/core';
const client = initClient(contract, { baseUrl: '/api' });
const { body } = await client.getPost({ params: { id: 'abc' } });
```

What you get:

- Contract is a plain TS object — easy to share across packages.
- Generates OpenAPI documents.
- Adapters for Express, Fastify, Nest, Next.js (App + Pages router), TanStack Query.
- Path-based routing with explicit HTTP methods — looks like REST in DevTools.

Where it bites:

- More verbose than tRPC for typical CRUD endpoints.
- React integration is solid but not as feature-rich as tRPC's.

## Programming Model Comparison

| Concept | tRPC v11 | oRPC | ts-rest |
|---------|----------|------|---------|
| Style | Procedure-first | Contract-first | Contract-first |
| Source of truth | Router | Contract object | Contract object |
| Transport | HTTP / WS / SSE / batch | HTTP / SSE / streams | HTTP |
| OpenAPI | Add-on | First-class | First-class |
| TanStack Query | Best in class | First-class | First-class |
| Subscriptions | Yes | Yes (SSE / streams) | No (SSE via plugin) |
| Multi-runtime | Yes | Yes | Yes |
| Mobile non-TS clients | Generate via codegen | OpenAPI → any client | OpenAPI → any client |
| Mature ecosystem | ✅ Largest | Growing | Mature for its niche |

## Where Server Actions Fit

Next.js Server Actions are not a replacement for any of these. They cover a specific case: a form on a page calls a function on the server, the page rerenders. They give you progressive enhancement and the right primitive for "submit a form, redirect."

What Server Actions don't give you:

- Reusable typed clients across many components.
- Calls from mobile apps or external services.
- Batching, subscription, or non-Next.js transports.
- Easy versioning or public API exposure.

A common 2026 pattern: Server Actions for forms that are tightly coupled to a page; tRPC / oRPC / ts-rest for reusable data fetching, mobile/external clients, and complex flows. See [trpc vs rest vs graphql in boilerplates](/guides/trpc-vs-rest-vs-graphql-boilerplates-2026) for the broader transport question.

## Boilerplate Adoption

| Boilerplate | RPC layer |
|-------------|-----------|
| Create T3 App | tRPC |
| T3 Turbo | tRPC |
| Makerkit Next.js | Server Actions + tRPC optional |
| Supastarter | Hono RPC + Server Actions |
| Next-Forge | Server Actions + tRPC optional |
| Indie Kit | Server Actions |
| Most premium kits | tRPC or Server Actions |

oRPC and ts-rest adoption is growing among boilerplates that explicitly target API-first SaaS — see [encore-ts vs hono vs elysia](/guides/encore-ts-vs-hono-vs-elysia-type-safe-backend-starters-2026) for the backend-framework dimension.

## Performance and Bundle Size

All three add modest client-bundle weight (5–15 KB gzipped depending on imports). Server-side overhead is negligible — they're thin wrappers over `fetch` and JSON.

The real performance dimension is **build time**. tRPC's router type inference scales with router size; very large routers can slow down `tsc`. oRPC and ts-rest scale better here because the contract is a plain object that doesn't infer through nested procedures.

## Choosing in 60 Seconds

- **TS-only boilerplate, no public API** → tRPC v11.
- **Public REST API + internal TS clients** → oRPC.
- **REST-style microservices, third-party clients** → ts-rest.
- **Just a form on a page** → Server Actions.

## Migration Notes

- **tRPC v10 → v11:** mostly mechanical; subscriptions and streaming changed.
- **tRPC → oRPC:** doable; oRPC ships a tRPC-compat layer for partial migrations.
- **REST handlers → ts-rest:** add a contract, swap your handlers, keep the same URLs.

## FAQ

**Does any of these replace REST entirely?** No. They are typed wrappers over HTTP (oRPC and ts-rest are explicit about this; tRPC hides it). REST clients can still call the endpoints; the "typed" benefit is on TS-aware callers.

**Edge runtime?** All three run on Cloudflare Workers, Vercel Edge, and Deno Deploy.

**File uploads?** All three support multipart and presigned-URL flows. Combined with [uploadthing or S3 in your boilerplate](/guides/uploadthing-vs-s3-vs-cloudflare-r2-starters-2026), the integration is straightforward.

**OpenFeature, OpenTelemetry?** All three integrate with OTel via middleware. Pair with [the SaaS observability stack](/guides/saas-observability-stack-2026).

---

*For backend-framework comparisons that influence which RPC layer fits, see [encore-ts vs hono vs elysia](/guides/encore-ts-vs-hono-vs-elysia-type-safe-backend-starters-2026).*

*For TanStack-Query-heavy boilerplates, also see [TanStack Start boilerplates](/guides/tanstack-start-boilerplates-starters-2026).*
