tRPC vs REST vs GraphQL in 2026: pick the right API layer for your team
The API layer question has a reputation for being tribal, but in 2026 the right answer is actually clearer than the debates suggest – because the use cases have separated more cleanly than they used to. tRPC v11 added React Server Component support, GraphQL Federation v2 matured into a genuine contract layer for large teams, and REST with OpenAPI 3.1 is the universal language for anything external. Here's how we think about the choice.
tRPC: maximum type safety, minimum ceremony
tRPC is the right call for TypeScript full-stack apps where the frontend and backend share a codebase or monorepo. You define procedures on the server, and the TypeScript types flow to the client automatically – no codegen, no schema files, no API contract to keep in sync. A type error in a backend procedure propagates to every client call site in the same build. For small-to-medium teams building product features fast, this eliminates a whole category of integration bugs.
// Server - define the procedure
const appRouter = router({
post: router({
byId: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => db.posts.findUnique({ where: { id: input.id } })),
}),
});
// Client - fully typed, no codegen, error if procedure changes
const { data } = trpc.post.byId.useQuery({ id: postId });
// data is typed from the server return type automatically
REST: the universal contract
REST with OpenAPI 3.1 is the right choice when your API will be consumed by clients you don't control: third-party integrations, mobile apps built by a separate team, webhook receivers, OAuth callbacks, and public developer APIs. The OpenAPI spec is a contract that any language, any tool, and any team can read. The 2026 tooling for REST has also improved significantly – `@hey-api/openapi-ts` and Zod OpenAPI generators close most of the type-safety gap that pushed teams to tRPC in the first place.
GraphQL: the right answer for diverse clients at scale
GraphQL earns its complexity when you have multiple client types (web, iOS, Android, third-party) that each need different shapes of the same underlying data. The query language lets clients request exactly what they need, the schema is self-documenting, and GraphQL Federation v2 gives you a scalable way to split the schema across teams without breaking client contracts. Below roughly ten engineers building for a single client, GraphQL's overhead rarely pays for itself.
The hybrid pattern that's emerged
The pattern used by most teams we've talked to: tRPC for the core application API (authenticated user-facing operations, internal product features), REST for external concerns (webhooks, OAuth callbacks, public API endpoints). The two coexist cleanly in a single codebase – tRPC handles the internal type-safe surface, REST handles everything that needs to be consumed outside the TypeScript monorepo boundary.
Decision table
- Team size < 5, TypeScript full-stack, single client: tRPC. Zero ceremony, maximum type safety, ships fastest.
- Public API or third-party consumers: REST + OpenAPI 3.1. The spec is the contract; type safety comes from generated clients.
- Multiple clients (web, mobile, third-party) with different data shape needs: GraphQL. The flexibility justifies the tooling investment at this scale.
- Mixed requirements: tRPC for internal + REST for external. The two compose naturally and don't force you to pick one for everything.

