tRPC Cheat Sheet

Quick reference for tRPC type-safe APIs. Router setup, procedures, middleware, React Query integration, error handling, and subscriptions — all in one page.

Server Setup Procedures (Queries & Mutations) Router & Merging Context & Middleware React Client Setup (v11) React Query Hooks Error Handling Subscriptions (WebSocket) Adapters

Server Setup

import { initTRPC } from "@trpc/server" Import tRPC
const t = initTRPC.context().create() Initialize with context type
export const router = t.router Export router builder
export const publicProcedure = t.procedure Export base procedure
export const appRouter = router({ ... }) Create root router
export type AppRouter = typeof appRouter Export router type for client

Procedures (Queries & Mutations)

.query(({ ctx }) => { ... }) Define a query (read data)
.mutation(({ ctx, input }) => { ... }) Define a mutation (write data)
.input(z.object({ id: z.string() })) Add input validation (Zod)
.output(z.object({ name: z.string() })) Add output validation
publicProcedure.input(z.string()).query(...) Chained: input → query
publicProcedure.input(z.object({...})).mutation(...) Chained: input → mutation

Router & Merging

const userRouter = router({ getById: ..., create: ... }) Create sub-router
const appRouter = router({ user: userRouter, post: postRouter }) Nest routers
const merged = router({ ...routerA._def.procedures, ...routerB._def.procedures }) Merge routers
// Client calls: trpc.user.getById.useQuery({ id }) Nested paths on client

Context & Middleware

export async function createContext(opts) { ... } Define context factory
t.middleware(async ({ ctx, next }) => { ... }) Create middleware
return next({ ctx: { user: ctx.session.user } }) Pass modified context
const protectedProcedure = publicProcedure.use(isAuthed) Create protected procedure
const adminProcedure = protectedProcedure.use(isAdmin) Chain middleware

React Client Setup (v11)

import { createTRPCReact } from "@trpc/react-query" Import React hooks
export const trpc = createTRPCReact() Create typed client
const [trpcClient] = useState(() => trpc.createClient({ links: [...] })) Create tRPC client
Wrap app with provider
httpBatchLink({ url: "/api/trpc" }) HTTP batching link
httpBatchStreamLink({ url: "/api/trpc" }) HTTP streaming link

React Query Hooks

trpc.user.getById.useQuery({ id: "1" }) Fetch data (query)
trpc.user.create.useMutation() Create mutation hook
mutation.mutate({ name: "Alice" }) Execute mutation
trpc.user.list.useInfiniteQuery({ limit: 10 }, { getNextPageParam }) Infinite query
trpc.user.list.useSuspenseQuery({}) Suspense-enabled query
const utils = trpc.useUtils() Get query utils (invalidate, prefetch)
utils.user.list.invalidate() Invalidate cached query
utils.user.getById.setData({ id }, updatedUser) Optimistic update

Error Handling

import { TRPCError } from "@trpc/server" Import error class
throw new TRPCError({ code: "NOT_FOUND" }) Throw typed error
throw new TRPCError({ code: "UNAUTHORIZED", message: "..." }) With custom message
throw new TRPCError({ code: "BAD_REQUEST", cause: zodError }) With cause
codes: NOT_FOUND, UNAUTHORIZED, FORBIDDEN, BAD_REQUEST Common error codes
codes: INTERNAL_SERVER_ERROR, TIMEOUT, TOO_MANY_REQUESTS More error codes

Subscriptions (WebSocket)

.subscription(({ input }) => observable(emit => { ... })) Define subscription
import { observable } from "@trpc/server/observable" Import observable
emit.next({ data: "hello" }) Emit data to client
wsLink({ client: createWSClient({ url: "ws://..." }) }) WebSocket link
trpc.onMessage.useSubscription({ }, { onData(msg) { ... } }) Subscribe on client

Adapters

import { fetchRequestHandler } from "@trpc/server/adapters/fetch" Fetch adapter (Edge)
import { createNextApiHandler } from "@trpc/server/adapters/next" Next.js Pages adapter
import { createExpressMiddleware } from "@trpc/server/adapters/express" Express adapter
import { fastifyTRPCPlugin } from "@trpc/server/adapters/fastify" Fastify adapter
app.use("/api/trpc", createExpressMiddleware({ router: appRouter })) Mount on Express

Try It Live

Test these patterns with our free API Tester. No signup needed.

Open API Tester →
Step-by-Step Guide

How to Test an API Online

Read Guide →

More Cheat Sheets