Full-stack type safety with Zod validation
Backend and frontend share the same types automatically
// backend: src/integrations/trpc/router.ts
import { z } from 'zod'
import { createTRPCRouter, publicProcedure } from './init'
const todosRouter = {
list: publicProcedure
.input(z.object({
filter: z.enum(['all', 'active', 'completed']).default('all'),
sortBy: z.enum(['name', 'createdAt', 'priority']).default('createdAt'),
search: z.string().optional(),
}).optional())
.query(({ input }) => {
// Type-safe input validation ✓
let todos = getTodos()
// Server-side filtering & sorting
if (input?.filter === 'active') {
todos = todos.filter(t => !t.completed)
}
return todos
}),
} satisfies TRPCRouterRecord// frontend: src/routes/demo/trpc-todo.tsx
import { useQuery } from '@tanstack/react-query'
import { useTRPC } from '@/integrations/trpc/react'
function TodoList() {
const trpc = useTRPC()
const { data, isLoading } = useQuery(
trpc.todos.list.queryOptions({
filter: 'active',
sortBy: 'createdAt',
search: 'project'
})
)
// data is automatically typed! ✓
// data?: Array<{
// id: number
// name: string
// completed: boolean
// priority: 'low' | 'medium' | 'high'
// createdAt: Date
// }>
}💡 Backend defines procedures with Zod input validation → Frontend gets autocomplete & type-safety automatically