tRPC for TypeScript: Complete Guide with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

What is tRPC and why do you need it?



tRPC (TypeScript Remote Procedure Call) is a modern library for creating type-safe APIs between client and server. The main feature of tRPC is that it does not require code generation or type duplication. You simply write functions on the server, and the client accesses them with full TypeScript support — autocompletion, type checking, and IntelliSense.



Unlike REST or GraphQL, where you need to manually describe schemas, endpoints, and types, tRPC automatically infers types from your server code. This radically simplifies development and reduces the number of errors.



Main advantages of tRPC:

  • Full type safety — type errors are detected at compile time, not at runtime
  • No code generation — no need to run generators or synchronize schemas
  • Minimal boilerplate — less code than in REST or GraphQL
  • Automatic documentation — types serve as documentation
  • Simplicity — works like a regular function call


tRPC is ideal for full-stack TypeScript applications (Next.js, Remix, Express, Fastify) and for microservice architecture.



Installing tRPC



tRPC consists of several packages. For basic usage you will need:



# Installing server and client partsnpm install @trpc/server @trpc/client

# Installing React adapter (if using React)npm install @trpc/react-query @tanstack/react-query

# Installing adapter for Next.jsnpm install @trpc/next @trpc/react-query @tanstack/react-query

# Installing Zod for validation (recommended)npm install zod


If you use yarn or pnpm:



yarn add @trpc/server @trpc/clientpnpm add @trpc/server @trpc/client


For Python developers (if you use Python on the backend): tRPC is a TypeScript library, but you can use it with Python via trpc-py (experimental wrapper). However, the main ecosystem is TypeScript.



Quick start with code example



Let's create a simple application: a server with procedures for working with users and a client that calls them.



1. Server (server.ts)



import { initTRPC } from '@trpc/server';import { z } from 'zod';

// Create a tRPC instanceconst t = initTRPC.create();

// Define the User typeinterface User { id: number; name: string; email: string;}

// Fake databaseconst users: User[] = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' },];

// Create a router with proceduresconst appRouter = t.router({ // Procedure to get all users getUsers: t.procedure .query(() => { return users; }),

// Procedure to get a user by ID getUserById: t.procedure .input(z.number()) .query(({ input }) => { return users.find(user => user.id === input) || null; }),

// Procedure to create a user createUser: t.procedure .input(z.object({ name: z.string().min(1), email: z.string().email(), })) .mutation(({ input }) => { const newUser: User = { id: users.length + 1, name: input.name, email: input.email, }; users.push(newUser); return newUser; }),});

// Export the router type for the clientexport type AppRouter = typeof appRouter;


2. Client (client.ts)



import { createTRPCClient, httpBatchLink } from '@trpc/client';import type { AppRouter } from './server';

// Create the clientconst client

Recommendations