GraphQL was never wrong. REST was never obsolete. tRPC is not the final answer either. Each one solves a different coordination problem, and the right choice depends more on team boundaries and consumers than on style preference.
What Each Approach Optimizes For
REST is strong when compatibility and HTTP semantics matter. It works well for public APIs, third-party consumers, and systems where the transport contract should stay language-agnostic.
GraphQL is strong when many clients need flexible reads against a shared schema. It centralizes the contract and gives clients control over shape, which is valuable when frontend needs vary.
tRPC is strongest when one TypeScript team owns both ends and wants fast type-safe iteration:
export const appRouter = router({
getUser: publicProcedure
.input(z.object({ id: z.string() }))
.query(({ input }) => db.user.findUnique({ where: { id: input.id } })),
});
That is powerful, but it assumes a fairly tight coupling model.
The Real Trade-Off
Each style moves complexity somewhere else:
- REST pushes more shape composition to clients
- GraphQL adds schema governance and resolver discipline
- tRPC ties you more closely to TypeScript and internal ownership boundaries
That is why API style is not ideology. It is an organizational design decision.
Better Rule
Choose based on consumers:
- public, broad, language-agnostic: REST
- many client shapes, one central schema: GraphQL
- single TypeScript org boundary, fast internal iteration: tRPC
The wrong move is using one style everywhere just to feel consistent.
Further Reading