tRPC gets praised as if it replaces every API style. It does not.
What it actually does very well is remove unnecessary coordination work inside a tightly coupled TypeScript stack. If your frontend and backend already live close together, and both are written in TypeScript, tRPC can cut a lot of duplicated typing and interface drift.
That is a real advantage. It is just not universal.
The Problem It Solves
In a lot of full-stack TypeScript apps, the same contract gets described three times:
- input validation
- backend handler types
- frontend consumer types
That duplication is where bugs and stale assumptions creep in.
tRPC collapses a lot of that by letting the client infer procedure types directly from the server router:
import { initTRPC } from "@trpc/server";
import { z } from "zod";
const t = initTRPC.create();
export const appRouter = t.router({
getUser: t.procedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return db.user.findById(input.id);
}),
});
export type AppRouter = typeof appRouter;
On the client side, you no longer hand-maintain a second version of the contract:
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "./server";
const trpc = createTRPCProxyClient<AppRouter>({
links: [httpBatchLink({ url: "/api/trpc" })],
});
const user = await trpc.getUser.query({ id: "123" });
That is the part people like: fewer handwritten seams.
Why It Feels So Good
tRPC is excellent when:
- the app is a monorepo or close equivalent
- TypeScript is the language on both sides
- the frontend is not meant to be a broad public API consumer
In that world, you get a very fast feedback loop. Rename a field on the server, and the client usually breaks at compile time instead of a week later in QA.
The Trade-Offs
tRPC is weaker when:
- multiple languages need to consume the API
- the API is public or partner-facing
- the backend and frontend evolve independently
- protocol-level contracts matter more than type inference convenience
That is where REST or gRPC usually makes more sense. Not because they are more modern, but because they are more decoupled.
A Better Framing
tRPC is not "the death of REST."
It is a very good fit for a specific category of product team:
- one organization
- one stack
- one shared type system
If that is your situation, it is a strong option.
If it is not, forcing tRPC into the architecture usually creates a different kind of coupling problem.
Further Reading