Quickstart
We highly encourage you to check out the Example Apps to get a feel of tRPC and getting up & running as seamless as possible.
Installation
⚠️ Requirements: tRPC requires TypeScript > 4.1 as it relies on Template Literal Types.
npm install @trpc/server
For implementing tRPC endpoints and routers. Install in your server codebase.
npm install @trpc/client @trpc/server
For making typesafe API calls from your client. Install in your client codebase (@trpc/server
is a peer dependency of @trpc/client
).
npm install @trpc/react react-query@3
For generating a powerful set of React hooks for querying your tRPC API. Powered by react-query.
npm install @trpc/next
A set of utilities for integrating tRPC with Next.js.
Installation Snippets
npm:
bash
npm install @trpc/server @trpc/client @trpc/react react-query@3 @trpc/next
bash
npm install @trpc/server @trpc/client @trpc/react react-query@3 @trpc/next
yarn:
bash
yarn add @trpc/server @trpc/client @trpc/react react-query@3 @trpc/next
bash
yarn add @trpc/server @trpc/client @trpc/react react-query@3 @trpc/next
Defining a router
Let's walk through the steps of building a typesafe API with tRPC. To start, this API will only contain two endpoints:
ts
getUser(id: string) => { id: string; name: string; }createUser(data: {name:string}) => { id: string; name: string; }
ts
getUser(id: string) => { id: string; name: string; }createUser(data: {name:string}) => { id: string; name: string; }
Create a router instance
First we define a router somewhere in our server codebase:
server.tsts
import * as trpc from '@trpc/server';const appRouter = trpc.router();// only export *type signature* of router!// to avoid accidentally importing your API// into client-side codeexport type AppRouter = typeof appRouter;
server.tsts
import * as trpc from '@trpc/server';const appRouter = trpc.router();// only export *type signature* of router!// to avoid accidentally importing your API// into client-side codeexport type AppRouter = typeof appRouter;
Add a query endpoint
Use the .query()
method to add a query endpoint to the router. Arguments:
.query(name: string, params: QueryParams)
name: string
: The name of this endpointparams.input
: Optional. This should be a function that validates/casts the input of this endpoint and either returns a strongly typed value (if valid) or throws an error (if invalid). Alternatively you can pass a Zod, Superstruct or Yup schema.params.resolve
: This is the actual implementation of the endpoint. It's a function with a singlereq
argument. The validated input is passed intoreq.input
and the context is inreq.ctx
(more about context later!)
server.tsts
import * as trpc from '@trpc/server';const appRouter = trpc.router().query('getUser', {input: (val: unknown) => {if (typeof val === 'string') return val;throw new Error(`Invalid input: ${typeof val}`);},async resolve(req) {req.input; // stringreturn { id: req.input, name: 'Bilbo' };},});export type AppRouter = typeof appRouter;
server.tsts
import * as trpc from '@trpc/server';const appRouter = trpc.router().query('getUser', {input: (val: unknown) => {if (typeof val === 'string') return val;throw new Error(`Invalid input: ${typeof val}`);},async resolve(req) {req.input; // stringreturn { id: req.input, name: 'Bilbo' };},});export type AppRouter = typeof appRouter;
Add a mutation endpoint
Similarly to GraphQL, tRPC makes a distinction between query and mutation endpoints. Let's add a createUser
mutation:
ts
createUser(payload: {name: string}) => {id: string; name: string};
ts
createUser(payload: {name: string}) => {id: string; name: string};
server.tsts
import * as trpc from '@trpc/server';import { z } from 'zod';const appRouter = trpc.router().query('getUser', {input: (val: unknown) => {if (typeof val === 'string') return val;throw new Error(`Invalid input: ${typeof val}`);},async resolve(req) {req.input; // stringreturn { id: req.input, name: 'Bilbo' };},}).mutation('createUser', {// validate input with Zodinput: z.object({ name: z.string().min(5) }),async resolve(req) {// use your ORM of choicereturn await UserModel.create({data: req.input,});},});export type AppRouter = typeof appRouter;
server.tsts
import * as trpc from '@trpc/server';import { z } from 'zod';const appRouter = trpc.router().query('getUser', {input: (val: unknown) => {if (typeof val === 'string') return val;throw new Error(`Invalid input: ${typeof val}`);},async resolve(req) {req.input; // stringreturn { id: req.input, name: 'Bilbo' };},}).mutation('createUser', {// validate input with Zodinput: z.object({ name: z.string().min(5) }),async resolve(req) {// use your ORM of choicereturn await UserModel.create({data: req.input,});},});export type AppRouter = typeof appRouter;
Next steps
tRPC includes more sophisticated client-side tooling designed for React projects generally and Next.js specifically. Read the appropriate guide next: