tRPC
Overview
tRPC enables end-to-end type-safe APIs by sharing TypeScript types between server and client without code generation or schemas. The server defines procedures (queries, mutations, subscriptions) in a router, and the client infers all types from the exported AppRouter type.
When to use: TypeScript full-stack apps needing type-safe API layers, monorepos sharing types, real-time subscriptions, rapid API iteration without OpenAPI/GraphQL overhead.
When NOT to use: Public APIs consumed by non-TypeScript clients (use REST/GraphQL), polyglot backends, projects requiring OpenAPI spec generation as primary output.
Quick Reference
| Pattern |
API |
Key Points |
| Initialize |
initTRPC.context<Ctx>().create() |
Single entry point, configure once |
| Router |
t.router({ ... }) |
Nest routers with t.mergeRouters() |
| Query |
t.procedure.input(schema).query(fn) |
Read operations, cached by clients |
| Mutation |
t.procedure.input(schema).mutation(fn) |
Write operations |
| Subscription |
t.procedure.subscription(fn) |
Real-time via WebSocket or SSE |
| Middleware |
t.middleware(fn) |
Chain with .use(), extend context via next({ ctx }) |
| Standalone middleware |
experimental_standaloneMiddleware<{}>() |
Reusable with explicit type constraints |
| Context |
createContext({ req, res }) |
Per-request, passed to all procedures |
| Server caller |
t.createCallerFactory(router) |
Type-safe server-side procedure calls |
| Error |
throw new TRPCError({ code, message }) |
Mapped to HTTP status codes |
| Error formatter |
initTRPC.create({ errorFormatter }) |
Customize error shape, expose Zod errors |
| Input validation |
.input(zodSchema) |
Multiple .input() calls merge (intersection) |
| Output validation |
.output(zodSchema) |
Strip extra fields from responses |
| React hooks |
trpc.useQuery() / trpc.useMutation() |
Built on @tanstack/react-query |
| React utils |
trpc.useUtils() |
Invalidate, prefetch, setData on cache |
| Suspense query |
trpc.useSuspenseQuery() |
Suspense-compatible data fetching |
| React subscription |
trpc.useSubscription(input, opts) |
onData callback for real-time events |
| Vanilla client |
createTRPCClient<AppRouter>({ links }) |
No React dependency |
| Batch link |
httpBatchLink({ url }) |
Batches requests in single HTTP call |
| Stream link |
httpBatchStreamLink({ url }) |
Streams responses as they resolve |
| WS link |
wsLink({ client: wsClient }) |
WebSocket transport for subscriptions |
| Split link |
splitLink({ condition, true, false }) |
Route operations to different transports |
| Logger link |
loggerLink() |
Debug request/response in development |
| Data transformer |
initTRPC.create({ transformer }) |
Serialize Dates, Maps, Sets (superjson) |
| Fetch adapter |
fetchRequestHandler({ endpoint, req }) |
Cloudflare Workers, Deno, Bun, Next.js |
| Procedure chaining |
publicProcedure.use(auth).use(rateLimit) |
Build reusable procedure bases |
Common Mistakes
| Mistake |
Correct Pattern |
Exporting the full t object |
Export only t.router, t.procedure, t.middleware, t.createCallerFactory |
| Creating context inside procedure |
Create context in adapter setup, flows through automatically |
Using any for context type |
Define context type with initTRPC.context<MyContext>().create() |
| Catching errors in procedures |
Let errors propagate; use onError in adapter or error formatter |
| Importing server code on client |
Import only type AppRouter, never runtime server code |
Using createCaller in production request handlers |
Use createCallerFactory for type-safe reusable callers |
| Defining input without validation |
Always validate with Zod, Valibot, or ArkType schemas |
| Nesting routers incorrectly |
Use dot notation in keys or t.mergeRouters(), not deep nesting |
| Different transformers on client/server |
Both sides must use the same transformer (e.g., superjson) |
| Creating QueryClient inside component render |
Create once outside component or use useState initializer |
| Manual TypeScript generics on hooks |
Type the router procedures; let inference propagate to client |
Not passing signal to fetch in queryFn |
tRPC React handles abort signals automatically |
Installation
pnpm add @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod
For subscriptions, add ws (server) and configure wsLink (client). For SSE-based subscriptions, use httpBatchStreamLink instead.
Delegation
- Procedure discovery: Use
Explore agent
- Router architecture review: Use
Task agent
- Code review: Delegate to
code-reviewer agent
If the tanstack-query skill is available, delegate query/mutation caching, invalidation, and optimistic update patterns to it.
If the zod-validation skill is available, delegate input schema design and validation patterns to it.
If the drizzle-orm skill is available, delegate database query patterns within procedures to it.
If the vitest-testing skill is available, delegate test runner configuration and assertion patterns to it.
If the hono skill is available, delegate Hono framework routing and middleware patterns to it.
References
- Router and procedure definitions
- Middleware and context patterns
- Error handling and formatting
- React client integration with @trpc/react-query
- Server-side callers and vanilla client
- Adapter setup for standalone, Express, Fastify, and Hono
- Subscriptions and real-time patterns
- Testing tRPC procedures
1---
2name: trpc
3description: |
4 tRPC v11 end-to-end type-safe APIs for TypeScript. Covers router and procedure definitions, input validation with Zod, middleware and context, subscriptions, error handling with TRPCError, React client hooks via @trpc/react-query, server-side callers with createCallerFactory, adapter setup (standalone, Express, Fastify, Hono), and testing patterns.
5
6 Use when building tRPC routers, defining procedures, setting up middleware, configuring adapters, integrating tRPC with React, handling errors, implementing subscriptions, or testing tRPC procedures.
7license: MIT
8metadata:
9 author: oakoss
10 version: '1.0'
11 source: 'https://trpc.io/docs'
12user-invocable: false
13---
14
15# tRPC
16
17## Overview
18
19tRPC enables end-to-end type-safe APIs by sharing TypeScript types between server and client without code generation or schemas. The server defines procedures (queries, mutations, subscriptions) in a router, and the client infers all types from the exported `AppRouter` type.
20
21**When to use:** TypeScript full-stack apps needing type-safe API layers, monorepos sharing types, real-time subscriptions, rapid API iteration without OpenAPI/GraphQL overhead.
22
23**When NOT to use:** Public APIs consumed by non-TypeScript clients (use REST/GraphQL), polyglot backends, projects requiring OpenAPI spec generation as primary output.
24
25## Quick Reference
26
27| Pattern | API | Key Points |
28| --------------------- | ------------------------------------------ | ------------------------------------------------------- |
29| Initialize | `initTRPC.context<Ctx>().create()` | Single entry point, configure once |
30| Router | `t.router({ ... })` | Nest routers with `t.mergeRouters()` |
31| Query | `t.procedure.input(schema).query(fn)` | Read operations, cached by clients |
32| Mutation | `t.procedure.input(schema).mutation(fn)` | Write operations |
33| Subscription | `t.procedure.subscription(fn)` | Real-time via WebSocket or SSE |
34| Middleware | `t.middleware(fn)` | Chain with `.use()`, extend context via `next({ ctx })` |
35| Standalone middleware | `experimental_standaloneMiddleware<{}>()` | Reusable with explicit type constraints |
36| Context | `createContext({ req, res })` | Per-request, passed to all procedures |
37| Server caller | `t.createCallerFactory(router)` | Type-safe server-side procedure calls |
38| Error | `throw new TRPCError({ code, message })` | Mapped to HTTP status codes |
39| Error formatter | `initTRPC.create({ errorFormatter })` | Customize error shape, expose Zod errors |
40| Input validation | `.input(zodSchema)` | Multiple `.input()` calls merge (intersection) |
41| Output validation | `.output(zodSchema)` | Strip extra fields from responses |
42| React hooks | `trpc.useQuery()` / `trpc.useMutation()` | Built on @tanstack/react-query |
43| React utils | `trpc.useUtils()` | Invalidate, prefetch, setData on cache |
44| Suspense query | `trpc.useSuspenseQuery()` | Suspense-compatible data fetching |
45| React subscription | `trpc.useSubscription(input, opts)` | `onData` callback for real-time events |
46| Vanilla client | `createTRPCClient<AppRouter>({ links })` | No React dependency |
47| Batch link | `httpBatchLink({ url })` | Batches requests in single HTTP call |
48| Stream link | `httpBatchStreamLink({ url })` | Streams responses as they resolve |
49| WS link | `wsLink({ client: wsClient })` | WebSocket transport for subscriptions |
50| Split link | `splitLink({ condition, true, false })` | Route operations to different transports |
51| Logger link | `loggerLink()` | Debug request/response in development |
52| Data transformer | `initTRPC.create({ transformer })` | Serialize Dates, Maps, Sets (superjson) |
53| Fetch adapter | `fetchRequestHandler({ endpoint, req })` | Cloudflare Workers, Deno, Bun, Next.js |
54| Procedure chaining | `publicProcedure.use(auth).use(rateLimit)` | Build reusable procedure bases |
55
56## Common Mistakes
57
58| Mistake | Correct Pattern |
59| --------------------------------------------------- | ------------------------------------------------------------------------------ |
60| Exporting the full `t` object | Export only `t.router`, `t.procedure`, `t.middleware`, `t.createCallerFactory` |
61| Creating context inside procedure | Create context in adapter setup, flows through automatically |
62| Using `any` for context type | Define context type with `initTRPC.context<MyContext>().create()` |
63| Catching errors in procedures | Let errors propagate; use `onError` in adapter or error formatter |
64| Importing server code on client | Import only `type AppRouter`, never runtime server code |
65| Using `createCaller` in production request handlers | Use `createCallerFactory` for type-safe reusable callers |
66| Defining input without validation | Always validate with Zod, Valibot, or ArkType schemas |
67| Nesting routers incorrectly | Use dot notation in keys or `t.mergeRouters()`, not deep nesting |
68| Different transformers on client/server | Both sides must use the same transformer (e.g., superjson) |
69| Creating QueryClient inside component render | Create once outside component or use useState initializer |
70| Manual TypeScript generics on hooks | Type the router procedures; let inference propagate to client |
71| Not passing `signal` to fetch in queryFn | tRPC React handles abort signals automatically |
72
73## Installation
74
75```bash
76pnpm add @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod
77```
78
79For subscriptions, add `ws` (server) and configure `wsLink` (client). For SSE-based subscriptions, use `httpBatchStreamLink` instead.
80
81## Delegation
82
83- **Procedure discovery**: Use `Explore` agent
84- **Router architecture review**: Use `Task` agent
85- **Code review**: Delegate to `code-reviewer` agent
86
87> If the `tanstack-query` skill is available, delegate query/mutation caching, invalidation, and optimistic update patterns to it.
88> If the `zod-validation` skill is available, delegate input schema design and validation patterns to it.
89> If the `drizzle-orm` skill is available, delegate database query patterns within procedures to it.
90> If the `vitest-testing` skill is available, delegate test runner configuration and assertion patterns to it.
91> If the `hono` skill is available, delegate Hono framework routing and middleware patterns to it.
92
93## References
94
95- [Router and procedure definitions](references/router-procedures.md)
96- [Middleware and context patterns](references/middleware-context.md)
97- [Error handling and formatting](references/error-handling.md)
98- [React client integration with @trpc/react-query](references/react-integration.md)
99- [Server-side callers and vanilla client](references/server-callers.md)
100- [Adapter setup for standalone, Express, Fastify, and Hono](references/adapter-setup.md)
101- [Subscriptions and real-time patterns](references/subscriptions.md)
102- [Testing tRPC procedures](references/testing-patterns.md)