Skip to content
>_devvkit
$devvkit learn --librarie trpc-guide

tRPC Guide

[typescript][api][rpc]
JavaScript / TypeScript
Install
npm install @trpc/server @trpc/client @trpc/react-query zod

tRPC eliminates the HTTP API layer. Write TypeScript functions on the server, call them from client.

Types flow from server to client with zero code generation — autocompletion for every API call.

Works with React, Next.js, Express. HTTP under the hood with batching and WebSocket subscriptions.

Server Setup

Init serverCreate tRPC instance.
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;

Router Definition

Query routerDefine read endpoint.
export const userRouter = router({
  list: publicProcedure.query(() => db.user.findMany()),
  byId: publicProcedure.input(z.string()).query(({input}) => db.user.findUnique({where:{id:input}})),
});
MutationDefine write endpoint.
createUser: publicProcedure.input(z.object({name:z.string(),email:z.string().email()}))
  .mutation(({input}) => db.user.create({data: input})),
Merge routersCombine routers.
export const appRouter = router({ user: userRouter, post: postRouter });
export type AppRouter = typeof appRouter;

Client Integration

Vanilla clientCall procedures.
const client = createTRPCClient<AppRouter>({ links: [httpBatchLink({url:'http://localhost:3000/trpc'})] });
await client.user.list.query();
await client.user.createUser.mutate({name:'Alice',email:'a@b.com'});

React Integration

React QueryReact hooks.
export const trpc = createTRPCReact<AppRouter>();
function Users() {
  const {data:users} = trpc.user.list.useQuery();
  const create = trpc.user.createUser.useMutation({onSuccess:() => trpc.user.list.useUtils().invalidate()});
}
Next.js adapterApp Router setup.
// app/api/trpc/[trpc]/route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
export { handler as GET, handler as POST };

Error Handling

Error handlingTyped TRPCError.
if (!user) throw new TRPCError({ code: 'NOT_FOUND', message: 'User not found' });

Advanced

Auth middlewareProtected procedure.
const authProcedure = publicProcedure.use(async ({ctx, next}) => {
  if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
  return next({ ctx: { ...ctx, user: ctx.user } });
});