Skip to main content

Guide

tRPC v11 vs oRPC vs ts-rest: Type-Safe RPC for SaaS Boilerplates 2026

Pick the right type-safe RPC layer for your SaaS boilerplate in 2026: tRPC v11, oRPC, and ts-rest compared on programming model, OpenAPI, edge support, and team fit.

StarterPick Team

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

ScenarioPick
Greenfield Next.js SaaS, TS client, no public APItRPC v11
You'll ship a public REST API to third-party developersoRPC or ts-rest
Mobile app + web app + maybe Python clientsoRPC (OpenAPI generation)
Microservices written in TS that need typed contractsts-rest
You like the contract-first style of OpenAPI / FastAPIoRPC
Tiny project, Server Actions cover itJust 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, 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.

// 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 })),
});
// 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.

// 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 } })),
  },
};
// 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.

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() }) },
  },
});
// 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 } }),
  }),
});
// 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

ConcepttRPC v11oRPCts-rest
StyleProcedure-firstContract-firstContract-first
Source of truthRouterContract objectContract object
TransportHTTP / WS / SSE / batchHTTP / SSE / streamsHTTP
OpenAPIAdd-onFirst-classFirst-class
TanStack QueryBest in classFirst-classFirst-class
SubscriptionsYesYes (SSE / streams)No (SSE via plugin)
Multi-runtimeYesYesYes
Mobile non-TS clientsGenerate via codegenOpenAPI → any clientOpenAPI → any client
Mature ecosystem✅ LargestGrowingMature 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 for the broader transport question.

Boilerplate Adoption

BoilerplateRPC layer
Create T3 ApptRPC
T3 TurbotRPC
Makerkit Next.jsServer Actions + tRPC optional
SupastarterHono RPC + Server Actions
Next-ForgeServer Actions + tRPC optional
Indie KitServer Actions
Most premium kitstRPC 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 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, the integration is straightforward.

OpenFeature, OpenTelemetry? All three integrate with OTel via middleware. Pair with the SaaS observability stack.


For backend-framework comparisons that influence which RPC layer fits, see encore-ts vs hono vs elysia.

For TanStack-Query-heavy boilerplates, also see TanStack Start boilerplates.

The SaaS Boilerplate Matrix (Free PDF)

20+ SaaS starters compared: pricing, tech stack, auth, payments, and what you actually ship with. Updated monthly. Used by 150+ founders.

Join 150+ SaaS founders. Unsubscribe in one click.