Overview
tRPC is an open-source framework designed for building type-safe APIs with TypeScript. Unlike traditional API approaches that often require schema definition languages like GraphQL's Schema Definition Language (SDL) or interface description languages (IDLs) such as those used by OpenAPI (Swagger), tRPC infers types directly from server-side TypeScript code. This approach aims to provide end-to-end type safety between the client and server without an explicit schema generation step or runtime validation.
The framework operates by defining server-side procedures that are strongly typed. When a client consumes these procedures, tRPC leverages TypeScript's inference capabilities to ensure that the client-side calls match the server-side definitions, including input parameters and output types. This eliminates a class of runtime errors related to API contract mismatches and reduces the manual effort associated with keeping client and server types synchronized.
tRPC is particularly suited for full-stack TypeScript applications, where both the frontend and backend are written in TypeScript. It integrates with modern frontend frameworks, including React, Next.js, and SvelteKit, and can be used with various Node.js server environments. Developers often choose tRPC for internal tools, dashboards, or applications where a unified TypeScript codebase can maximize developer productivity and reduce boilerplate code for data fetching and mutation operations.
The core components of tRPC include a server library for defining API procedures and a client library for consuming them. The server defines routers and procedures, which are functions that accept input and return output, all with inferred types. The client then interacts with these procedures using a type-safe client proxy. This design aims to offer a developer experience where API interactions feel like calling local functions rather than making remote network requests, while maintaining type guarantees across the entire application stack. The project was founded in 2021 and primarily supports TypeScript as its development language.
Key features
- End-to-end type safety: Provides type inference for API calls from client to server, ensuring inputs and outputs match without manual type definitions or code generation tRPC concepts documentation.
- No code generation: Eliminates the need for separate schema generation steps or tooling, simplifying the development workflow.
- Reduced boilerplate: Streamlines API development by inferring types and handling data fetching logic, reducing repetitive code for common operations.
- Full-stack TypeScript integration: Designed for seamless integration within projects where both the frontend and backend are written in TypeScript.
- Framework agnostic server: Can be used with various Node.js server frameworks, including Express, Fastify, and Hono tRPC server adapters.
- Client-side framework integrations: Offers specific adapters for popular frontend libraries such as React Query, facilitating efficient data fetching and caching tRPC React Query integration.
- Small bundle size: The client library is designed to be lightweight, contributing to smaller application bundle sizes.
- Developer experience: Aims to make API interactions feel like local function calls, improving development speed and reducing debugging time related to type mismatches.
Pricing
tRPC is a fully open-source project distributed under the MIT License.
| Feature | Availability | Notes |
|---|---|---|
| Core tRPC library | Free | Includes server and client packages, fully open-source. |
| Type inference | Free | Core functionality for end-to-end type safety. |
| Integrations (e.g., React Query) | Free | All official integration packages are open-source. |
| Community support | Free | Available via GitHub discussions and Discord. |
As of 2026-05-07, all core products and ecosystem tools for tRPC are available without cost, as detailed on the tRPC homepage.
Common integrations
- React Query: Integrates with
@tanstack/react-queryfor data fetching, caching, and state management in React applications tRPC React Query documentation. - Next.js: Seamlessly integrates with Next.js for full-stack applications, often used with API routes or App Router tRPC Next.js integration guide.
- SvelteKit: Can be used with SvelteKit for type-safe API interactions in Svelte applications tRPC SvelteKit documentation.
- Express.js: tRPC servers can be hosted on Express.js using the
@trpc/server/adapters/expressadapter tRPC server adapters. - Fastify: Support for Fastify servers via the
@trpc/server/adapters/fastifyadapter Fastify documentation. - Hono: Compatible with Hono for lightweight server environments, particularly in edge functions tRPC Hono adapter.
- Zod: Commonly used for input validation and schema definition within tRPC procedures, leveraging Zod's schema inference tRPC input validation documentation.
Alternatives
- GraphQL: A query language for APIs that allows clients to request exactly the data they need, often requiring a schema definition language and code generation for type safety GraphQL official website.
- OpenAPI (Swagger): A specification for machine-readable interface files for describing, producing, consuming, and visualizing RESTful web services, typically relying on code generation for client-side type safety OpenAPI Specification.
- gRPC: A high-performance, open-source universal RPC framework that uses Protocol Buffers for defining service contracts and supports multiple languages gRPC project page.
Getting started
To get started with tRPC, you typically set up a server defining procedures and a client to consume them. Below is a basic example illustrating a simple tRPC setup with a server and client, demonstrating end-to-end type safety.
// src/server/index.ts (tRPC Server)
import { initTRPC } from '@trpc/server';
import { z } from 'zod'; // Used for input validation
// Initialize tRPC
const t = initTRPC.create();
// Create a router
const appRouter = t.router({
hello: t.procedure
.input(z.object({ name: z.string().optional() }))
.query(({ input }) => {
return `Hello ${input?.name || 'world'}!`;
}),
addUser: t.procedure
.input(z.object({ name: z.string(), email: z.string().email() }))
.mutation(({ input }) => {
// In a real app, you'd save to a database
console.log('Adding user:', input);
return { id: Math.random().toString(36).substring(7), ...input };
}),
});
// Export type router type signature, this is used by the client
export type AppRouter = typeof appRouter;
// Example: How to set up a basic HTTP server with tRPC (e.g., using Express)
// This part would typically be in a separate file like `src/server/start.ts`
import * as express from 'express';
import * as trpcExpress from '@trpc/server/adapters/express';
const app = express();
app.use(
'/trpc',
trpcExpress.createExpressMiddleware({
router: appRouter,
}),
);
const port = 3000;
app.listen(port, () => {
console.log(`Server listening on http://localhost:${port}`);
});
// src/client/index.ts (tRPC Client)
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '../server'; // Import the server's AppRouter type
const trpc = createTRPCProxyClient({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
],
});
async function main() {
// Calling a query
const helloResult = await trpc.hello.query({ name: 'fwdgrade' });
console.log('Query result:', helloResult);
const defaultHelloResult = await trpc.hello.query();
console.log('Default query result:', defaultHelloResult);
// Calling a mutation
const newUser = await trpc.addUser.mutate({
name: 'Jane Doe',
email: '[email protected]',
});
console.log('Mutation result (new user):', newUser);
// Example of type error (will be caught at compile time):
// await trpc.hello.query({ unknownProp: 'value' }); // Type error: 'unknownProp' does not exist
// await trpc.addUser.mutate({ name: 'John Doe' }); // Type error: 'email' is missing
}
main().catch(console.error);
This example demonstrates how the AppRouter type from the server is imported into the client, allowing the client to have full type-safety for all API calls. The zod library is used for input validation, ensuring that incoming data to server procedures conforms to expected types tRPC Zod integration. When the client makes a call like trpc.hello.query({ name: 'fwdgrade' }), TypeScript checks that name is a string, and if name were omitted, it would highlight a type error if the input was not optional. Similarly, for mutations like addUser, both name and email are required, and the TypeScript compiler would flag any missing or incorrectly typed fields.