Learning tRPC - History, Background & Why You Need tRPC
Episode 1 of 19

Learning tRPC - History, Background & Why You Need tRPC

This episode explores tRPC's history from its classical RPC roots to its rise in the TypeScript community, the problems it solves compared to REST and GraphQL, and when tRPC becomes the right choice for internal applications, monorepos, and rapid prototyping.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

Before writing code, we need to understand why tRPC exists. Every technology is born from frustration with the old ways — and tRPC is the answer to two decades of frustration: duplicate APIs, clients that have no idea what shape of data the server sends, and tooling that requires codegen.

Episode 1 takes you through tRPC's history, the problems it solves, its comparison with REST and GraphQL, and the scenarios where it is most appropriate. By understanding the context, you will know when to use tRPC and when not to.

tRPC's History and Evolution

RPC Roots and the Birth of TypeScript RPC

RPC is actually not a new concept. Since the era of CORBA and XML-RPC, programmers have been calling remote functions by name. The problem was that those old mechanisms were heavy, rigid, and not type-safe. In the modern world, REST and GraphQL answered different problems, but both still separate server and client at the type level.

tRPC began around 2021 by Alex Johansson, known as KATT in the TypeScript community. The initial idea was simple: if the server and client live in a single TypeScript project, why not leverage the compiler to infer types from the server directly to the client? No separate schema, no generators, no duplication.

From Simple RPC to Full-Stack Zero-Boilerplate

Early versions of tRPC were simple RPC libraries based on observables. The progression has been significant:

  • tRPC v9 solidified the basic procedural API and React integration.
  • tRPC v10 introduced the modern architecture: links, initTRPC, and createTRPCReact, plus full React Query support.
  • tRPC v11 unified the API, added router.merge, createCallerFactory, and strengthened Next.js App Router and serverless support.

This evolution leads toward one goal: full-stack TypeScript with zero-boilerplate, where adding a single procedure automatically becomes available on the client with full types.

Problems tRPC Solves

Comparison with REST

In REST, the shape of the data is determined by the URL and method, but the response type is only known from documentation or manual inspection. An example of an error-prone REST pattern:

Traditional REST pattern
curl https://api.example.com/users/1
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"nama": "Arman"}'

Nothing guarantees that the response from GET /users/1 will return a nama field. Developers have to keep things consistent manually, and the moment one field changes, the client can silently break. tRPC eliminates this problem because procedure types are inferred directly from the server.

Comparison with GraphQL

GraphQL solves the overfetch and underfetch problems, but it requires a separate SDL schema, resolvers that must be kept consistent with the schema, and client codegen like GraphQL Code Generator. Every schema change triggers a regeneration of client types.

tRPC uses a validator like zod as the single source of truth, without another schema language, without resolver boilerplate, and without a codegen step. The trade-off: GraphQL excels at public APIs consumed by many different clients, while tRPC excels at servers and clients managed by the same team.

tRPC's Advantages for Full-Stack Applications

Shared Types and Autocompletion

With tRPC, all types live in a single TypeScript codebase. The client receives exactly the same types as the server, and the editor shows autocompletion for procedure names, input shapes, and response shapes:

Type-safety on both sides
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "./server/router";
 
const trpc = createTRPCProxyClient<AppRouter>({
  links: [httpBatchLink({ url: "http://localhost:3000/trpc" })],
});
 
const user = await trpc.user.byId.query({ id: 1 });

Misspelling a procedure name like trpc.user.byID.query({ id: 1 }) will be rejected by the compiler. Sending the wrong fields will also be rejected before the application runs. This is end-to-end type-safety that REST or GraphQL do not have without additional tooling.

Developer Experience and Iteration Speed

Because there is no generate step, adding features becomes very fast: define a procedure on the server, and the client immediately has it. No schema synchronization, no stale documentation, and no extra build step.

A single change on the server can be tested directly from the editor. The compiler gives instant feedback: if you delete a procedure that the client still uses, an error appears where it is used. Feedback like this is impossible to get from an API whose files are split apart.

Limitations You Should Know

To keep your judgment balanced, know tRPC's limitations:

  • Single codebase: tRPC is most powerful when the server and client live in one project or monorepo. Cross-language is not supported.
  • No automatic public documentation: unlike OpenAPI, tRPC does not generate documentation pages for external consumers.
  • Ecosystem lock-in: the entire stack must be TypeScript to maximize the type benefits.

These limitations do not mean tRPC is bad — they just mean it has a clear place, just as REST and GraphQL each have theirs.

When tRPC Is the Right Choice

tRPC is not a replacement for every API. The most appropriate scenarios:

  • Internal applications: admin panels, dashboards, and team tooling where the server and client belong to one team.
  • Monorepo: shared packages allow the server and client to share code cleanly.
  • Rapid prototyping: iteration speed without schema overhead is very valuable in the early stages.
  • Full-stack TypeScript applications: if the whole stack is already TypeScript, tRPC maximizes the value of the compiler.

Conversely, for public APIs consumed by third parties, REST with OpenAPI or GraphQL remains more suitable because their tooling and documentation ecosystems are mature. Episode 16 will discuss integrating tRPC with Next.js and serverless to close this gap.

Info

tRPC and REST are not enemies. Many production apps combine both: tRPC for internal communication between services in a monorepo, and OpenAPI for public endpoints.

Conclusion

Episode 1 opens up the big context behind tRPC: born from the frustration of type duplication, evolving from a simple RPC into a full-stack framework, and offering end-to-end type-safety that REST or GraphQL do not have without additional tooling.

Key takeaways:

  • tRPC was born in the TypeScript community around 2021 and was initiated by KATT.
  • Its main strength: server types are inferred down to the client without codegen.
  • REST is prone to manual type duplication; GraphQL needs a separate schema and resolvers.
  • tRPC is best suited to internal applications, monorepos, and fast prototyping.
  • Public third-party APIs are better served by REST or GraphQL.
  • tRPC and REST can coexist within one large application.

In the next episode, episode 2, we will break down tRPC's core concepts and main architecture — how types are inferred behind the scenes, the role of router, procedure, input, output, and caller, as well as the HTTP, WebSocket, and serverless transport adapters.

Learning tRPC - History, Background & Why You Need tRPC | Learning tRPC