- Published on
What is tRPC? Build End-to-End Typesafe APIs in 2026
tRPC (TypeScript Remote Procedure Call) is a framework that allows you to build end-to-end typesafe APIs without needing a separate translation layer like REST or GraphQL. By leveraging TypeScript's type inference, it ensures that your frontend code automatically knows exactly what data your backend expects, reducing integration bugs by up to 90%. You can set up a fully functional, typesafe connection between a Next.js 15 client and a server in under 10 minutes.
What are the prerequisites for using tRPC?
Before you start building, you need a few modern tools installed on your machine. Because tRPC relies heavily on the latest TypeScript features, using updated versions is non-negotiable for a smooth experience.
- Node.js 22.0 or higher: This is the runtime (the environment that runs JavaScript on your computer) that handles your server-side code.
- TypeScript 5.7 or higher: You need a recent version of TypeScript to handle the complex "type inference" (the way the computer figures out what kind of data you are using) that tRPC performs.
- A Package Manager: You should have npm, pnpm, or yarn installed to manage your project libraries.
- Basic React Knowledge: Since most people use tRPC with frameworks like React 19 or Next.js 15, knowing how components work will help you follow along.
Why is tRPC better than traditional REST APIs?
In a traditional REST (Representational State Transfer) setup, your frontend and backend are two separate islands. When the backend developer changes a data field from a "number" to a "string," the frontend often breaks because it doesn't know about the change until the app crashes. You usually have to manually write "interfaces" (descriptions of what data looks like) on both sides to keep them in sync.
tRPC removes this manual work by sharing the actual code definitions between the server and the client. If you change a variable name on your server, your frontend code will immediately show a red underline error in your code editor. This "compile-time" (the period when your code is checked for errors before running) feedback prevents you from shipping broken code to your users.
We've found that this eliminates the "guessing game" often associated with API documentation. Instead of checking a separate website to see what an API returns, your code editor simply tells you via autocomplete. This creates a much faster workflow where you spend less time debugging and more time building features.
How do you set up a basic tRPC server?
Setting up the server involves creating a "router" (a map of all the functions your API can perform). Each function in the router is called a "procedure."
Step 1: Install the core libraries
Open your terminal in your project folder and run the following command:
npm install @trpc/server @trpc/client zod
Step 2: Initialize the tRPC backend
Create a file named trpc.ts. This is where you initialize the library.
import { initTRPC } from '@trpc/server';
// This creates the main tRPC object
const t = initTRPC.create();
// We export these to use them in our router
export const router = t.router;
export const publicProcedure = t.procedure;
Step 3: Create your first router
Now, create a file named index.ts to define what your API actually does. We will use Zod (a library used to validate that data is the correct type) to check the input.
import { z } from 'zod';
import { router, publicProcedure } from './trpc';
export const appRouter = router({
// This defines a procedure called 'getUser'
getUser: publicProcedure
.input(z.string()) // We expect a string (the user ID)
.query((opts) => {
// opts.input is the string we passed in
return { id: opts.input, name: 'Alex', role: 'Developer' };
}),
});
// This line is the "magic" - it exports the types for the client
export type AppRouter = typeof appRouter;
How do you connect the client to the server?
Once the server is defined, the client needs to know where to find it. The "magic" happens when we import the AppRouter type we created in the previous step.
Step 1: Create the tRPC client
In your frontend folder, create a file called client.ts.
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server/index'; // Import ONLY the type
// Create the client with the server's URL
export const trpc = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
],
});
Step 2: Use the client in your code Now you can call your backend functions just like they were local functions in your file.
// This is how you call the 'getUser' procedure
const user = await trpc.getUser.query('user_123');
console.log(user.name); // Output: 'Alex'
What you should see is your code editor suggesting id, name, and role as soon as you type user.. If you try to access user.email, TypeScript will give you an error because that field doesn't exist on the server.
What are the common mistakes beginners make?
One common mistake is trying to import the actual server code into the frontend. You should only import the type (using import type) to keep your frontend bundle small. If you accidentally import the whole router, your frontend might try to run server-only code like database connections, which will cause a crash.
Another hurdle is forgetting to validate inputs using Zod. Beginners often skip the .input() step in a procedure to save time. However, without this validation, tRPC cannot provide the "autocomplete" feature on the client side because it doesn't know what data the client is supposed to send.
Finally, many new users struggle with "CORS" (Cross-Origin Resource Sharing - a security feature that stops websites from talking to different domains). If your frontend is on localhost:3000 and your server is on localhost:4000, you must tell your server to allow requests from the frontend. If you see a "CORS error" in your browser console, this is usually the culprit.
Is tRPC right for your project?
tRPC is a fantastic choice if you are building a "Monorepo" (a project where the frontend and backend live in the same code folder). It works best when both your frontend and backend are written in TypeScript. If your backend is written in a different language like Python or Go, tRPC isn't the right tool for you, as it relies on TypeScript's ability to share definitions.
Don't worry if the setup feels a bit heavy at first with files like trpc.ts and client.ts. Once those are in place, adding new API features becomes incredibly fast. You will spend much less time writing documentation and much more time actually shipping your product.
Next Steps
To get the most out of tRPC, we recommend looking into how it integrates with "TanStack Query" (a tool for managing data fetching and loading states). This combination is the industry standard for building modern, responsive web applications in 2026. You should also explore "Mutations," which are tRPC procedures used for changing data, such as saving a new user to a database.