trpc-type-safety
tRPC end-to-end type-safe APIs for TypeScript with React Query integration and full-stack type safety
What this skill does
# tRPC - End-to-End Type Safety
---
progressive_disclosure:
entry_point: summary
sections:
- id: summary
title: "tRPC Overview"
tokens: 70
next: [when_to_use, quick_start]
- id: when_to_use
title: "When to Use tRPC"
tokens: 150
next: [quick_start, core_concepts]
- id: quick_start
title: "Quick Start"
tokens: 300
next: [core_concepts, router_definition]
- id: core_concepts
title: "Core Concepts"
tokens: 400
next: [router_definition, procedures]
- id: router_definition
title: "Router Definition"
tokens: 350
next: [procedures, context]
- id: procedures
title: "Procedures (Query & Mutation)"
tokens: 400
next: [input_validation, context]
- id: input_validation
title: "Input Validation with Zod"
tokens: 350
next: [context, middleware]
- id: context
title: "Context Management"
tokens: 400
next: [middleware, error_handling]
- id: middleware
title: "Middleware"
tokens: 400
next: [error_handling, client_setup]
- id: error_handling
title: "Error Handling"
tokens: 350
next: [client_setup, react_integration]
- id: client_setup
title: "Client Setup"
tokens: 400
next: [react_integration, nextjs_integration]
- id: react_integration
title: "React Query Integration"
tokens: 450
next: [nextjs_integration, subscriptions]
- id: nextjs_integration
title: "Next.js App Router Integration"
tokens: 500
next: [subscriptions, file_uploads]
- id: subscriptions
title: "Real-time Subscriptions"
tokens: 400
next: [file_uploads, batching]
- id: file_uploads
title: "File Uploads"
tokens: 300
next: [batching, typescript_inference]
- id: batching
title: "Batch Requests & Data Loaders"
tokens: 350
next: [typescript_inference, testing]
- id: typescript_inference
title: "TypeScript Inference Patterns"
tokens: 300
next: [testing, production_patterns]
- id: testing
title: "Testing Strategies"
tokens: 400
next: [production_patterns, comparison]
- id: production_patterns
title: "Production Patterns"
tokens: 450
next: [comparison, migration]
- id: comparison
title: "Comparison with REST & GraphQL"
tokens: 250
next: [migration, best_practices]
- id: migration
title: "Migration from REST"
tokens: 300
next: [best_practices]
- id: best_practices
title: "Best Practices & Performance"
tokens: 400
---
## Summary
**tRPC** enables end-to-end type safety between TypeScript clients and servers without code generation. Define your API once, get automatic type inference everywhere.
**Key Benefits**: Zero codegen, TypeScript inference, React Query integration, minimal boilerplate.
---
## When to Use tRPC
**✅ Perfect For**:
- Full-stack TypeScript applications (Next.js, T3 stack)
- Projects where client and server share TypeScript codebase
- Teams wanting REST-like simplicity with GraphQL-like type safety
- Apps using React Query for data fetching
- Internal APIs where you control both client and server
**❌ Avoid When**:
- Public APIs consumed by non-TypeScript clients
- Microservices in different languages
- Mobile apps using Swift/Kotlin (use REST/GraphQL instead)
- Need API documentation for external developers (OpenAPI better)
**When to Choose**:
- **tRPC**: Full-stack TypeScript, monorepo, internal tools
- **REST**: Public APIs, language-agnostic, broad compatibility
- **GraphQL**: Complex data graphs, multiple clients, flexible queries
---
## Quick Start
### Installation
```bash
# Server dependencies
npm install @trpc/server zod
# React/Next.js client dependencies
npm install @trpc/client @trpc/react-query @tanstack/react-query
```
### Define Router (Server)
```typescript
// server/trpc.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
export const appRouter = t.router({
hello: t.procedure
.input(z.object({ name: z.string() }))
.query(({ input }) => {
return { greeting: `Hello ${input.name}` };
}),
createPost: t.procedure
.input(z.object({ title: z.string(), content: z.string() }))
.mutation(async ({ input }) => {
// Save to database
return { id: 1, ...input };
}),
});
export type AppRouter = typeof appRouter;
```
### Use in Client (React)
```typescript
// client/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server/trpc';
export const trpc = createTRPCReact<AppRouter>();
// Component
function MyComponent() {
const { data } = trpc.hello.useQuery({ name: 'World' });
const createPost = trpc.createPost.useMutation();
return <div>{data?.greeting}</div>; // Fully typed!
}
```
**Next**: Learn core concepts or dive into router definition.
---
## Core Concepts
### The tRPC Philosophy
tRPC provides **type-safe remote procedure calls** by sharing TypeScript types between client and server. No code generation—just TypeScript's inference.
### Key Components
1. **Router**: Collection of procedures (API endpoints)
2. **Procedure**: Single API operation (query or mutation)
3. **Context**: Request-scoped data (user, database, etc.)
4. **Middleware**: Intercept/modify requests (auth, logging)
5. **Input/Output**: Validated with Zod schemas
### Type Flow
```typescript
// Server defines types
const router = t.router({
getUser: t.procedure
.input(z.string())
.query(({ input }) => ({ id: input, name: 'Alice' })),
});
// Client gets automatic types
const user = await trpc.getUser.query('123');
// user is typed as { id: string, name: string }
```
### Architecture Pattern
```
┌─────────────┐ Type-safe ┌──────────────┐
│ Client │ ←────────────────→ │ Server │
│ (React) │ No codegen! │ (Node.js) │
└─────────────┘ └──────────────┘
↓ ↓
React Query tRPC Router
(caching) (procedures)
```
**Advantages**:
- Changes propagate instantly (no build step)
- Rename refactoring works across client/server
- Impossible to call wrong types
- Auto-complete for all API methods
---
## Router Definition
### Basic Router Structure
```typescript
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
export const appRouter = t.router({
// Procedures go here
});
export type AppRouter = typeof appRouter;
```
### Nested Routers (Namespacing)
```typescript
const userRouter = t.router({
getById: t.procedure
.input(z.string())
.query(({ input }) => getUser(input)),
create: t.procedure
.input(z.object({ name: z.string(), email: z.string() }))
.mutation(({ input }) => createUser(input)),
});
const postRouter = t.router({
list: t.procedure.query(() => getPosts()),
create: t.procedure
.input(z.object({ title: z.string() }))
.mutation(({ input }) => createPost(input)),
});
export const appRouter = t.router({
user: userRouter,
post: postRouter,
});
// Client usage:
// trpc.user.getById.useQuery('123')
// trpc.post.list.useQuery()
```
### Router Merging
```typescript
import { adminRouter } from './admin';
import { publicRouter } from './public';
export const appRouter = t.mergeRouters(publicRouter, adminRouter);
```
### Router Organization Best Practices
```
server/
├── trpc.ts # tRPC instance, context, middleware
├── routers/
│ ├── user.ts # User-related procedures
│ ├── post.ts # Post-related procedures
│ └── index.ts # Combine all routers
└── index.ts # Export AppRouter type
```
---
## Procedures (Query & Mutation)
### Query Procedures (Read Operations)
```typescript
const router = t.router({
// Simple query
getUser: t.procedure
Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.