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 |
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
Read Guide →