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, 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
| 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 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 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.