trpc/trpc

🧙‍♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy.

40,027 stars TypeScript 8 components

12 hidden assumptions · 7-stage pipeline · 8 components

Like any codebase, this library makes assumptions it never checks — most are routine. The ones worth your attention are below.

Builds end-to-end type-safe APIs with client libraries for React, Next.js, and framework adapters

The system follows a request-response pattern where clients make type-safe procedure calls that are validated, executed on the server, and return typed results. The flow starts with procedure definitions on the server, generates TypeScript types for the client, and enables end-to-end type safety through the entire API lifecycle.

Under the hood, the system uses 3 feedback loops, 3 data pools, 4 control points to manage its runtime behavior.

A 8-component library. 983 files analyzed. Data flows through 7 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If server returns malformed error responses with missing or incorrectly-typed 'data' fields, clients receive TRPCClientError with undefined/invalid this.data property, breaking error handling code that expects specific error data structures

Worth your attention first

If opts.config() returns a malformed client or clientCallTypeToProcedureType returns unexpected procedure types, the proxy crashes at runtime with 'undefined is not a function' when trying to call client[procedureType]

Worth your attention first

If called with empty path array, pathCopy.pop() returns undefined, causing action to be undefined and procedureType lookup to fail, resulting in runtime errors when trying to access client[undefined]

Show everything (9 more)
Domain

query object passed to querySerializer contains only serializable values that URLSearchParams can handle, but never validates value types - assumes no nested objects, functions, or circular references

If this fails: If query contains complex objects, functions, or circular references, URLSearchParams silently converts them to '[object Object]' or throws, producing invalid query strings that break API calls

packages/openapi/src/heyapi/index.ts:createTRPCHeyApiClientConfig
Resource

React Query's cache can handle the generated query keys without memory issues - assumes keys are reasonably sized and don't contain large objects that would bloat the cache

If this fails: If procedures have large input objects as parameters, query keys become massive and consume excessive memory in React Query's cache, potentially causing browser crashes or severe performance degradation

packages/react-query/src/index.ts:getQueryKey
Temporal

opts.config() returns the same configuration on every call within a single request, allowing safe caching with React's cache() function - assumes config is static during request lifecycle

If this fails: If config changes between calls (e.g., based on request headers or dynamic context), cache returns stale client configurations, causing requests to use wrong endpoints, auth tokens, or transforms

packages/next/src/app-dir/server.ts:getClient cache
Environment

AWS Lambda runtime provides the expected APIGWContext object structure and event formats matching LambdaEvent interface, but never validates the runtime environment or context shape

If this fails: If deployed to non-AWS environments or newer Lambda runtime versions change context structure, planner.request and planner.path extraction fails silently, causing request routing to break without clear error messages

packages/server/src/adapters/aws-lambda/index.ts:awsLambdaRequestHandler
Scale

TypeScript program can load and analyze all source files in memory simultaneously - assumes codebase size fits in available memory without considering large monorepos or projects with thousands of files

If this fails: On large codebases, getProgram() consumes excessive memory and may crash with out-of-memory errors, making the upgrade tool unusable for enterprise-scale projects

packages/upgrade/src/bin/index.ts:getProgram
Contract

fetchRequestHandler from @trpc/server/adapters/fetch expects a standard Request object and returns a Response, but never validates that Bun's fetch API contract matches Node.js/browser standards

If this fails: If Bun's Request/Response implementations have subtle differences from standard Web APIs, request parsing or response formatting may fail in production, causing silent data corruption or unexpected errors

examples/bun/src/index.ts:fetchRequestHandler
Environment

Cloudflare Workers runtime provides the expected WorkerEntrypoint class and supports standard fetch RequestHandler pattern, but never validates runtime capabilities or API availability

If this fails: If deployed to older Cloudflare Workers runtime or if WorkerEntrypoint API changes, the service fails to initialize properly, causing all tRPC requests to return 500 errors without clear debugging information

examples/cloudflare-workers/src/index.ts:TRPCCloudflareWorkerExample
Domain

OpenAPI schema format values 'date-time' and 'date' always map correctly to JavaScript Date objects, but doesn't account for timezone handling, invalid date strings, or different date serialization formats

If this fails: When API returns dates in unexpected formats or timezones, the generated client code creates invalid Date objects, causing date calculations to produce wrong results or NaN values in UI components

packages/openapi/src/heyapi/index.ts:createTRPCHeyApiTypeResolvers
Contract

Error responses follow the exact structure with nested error.code and error.message properties, but doesn't validate that the full error shape matches what downstream error handlers expect (e.g., missing error.data)

If this fails: Partial error responses that pass basic validation but lack expected error.data fields cause error boundaries and user error handling to receive incomplete error information, leading to generic error messages instead of specific user-facing errors

packages/client/src/TRPCClientError.ts:isTRPCErrorResponse

Open the standalone hidden-assumptions report for trpc →

How Data Flows Through the System

The system follows a request-response pattern where clients make type-safe procedure calls that are validated, executed on the server, and return typed results. The flow starts with procedure definitions on the server, generates TypeScript types for the client, and enables end-to-end type safety through the entire API lifecycle.

  1. Define API Schema — Developers use initTRPC to create routers with procedures that define input validation (Zod schemas), business logic (resolvers), and output types
  2. Generate Client Types — TypeScript compiler extracts procedure signatures from router to generate client-side types without runtime code generation [Router]
  3. Create Client Instance — createTRPCClient builds a type-safe proxy using the router types and configures links for request handling (HTTP, WebSocket, batching)
  4. Make Procedure Call — Client calls procedures through the proxy, which validates inputs locally and constructs TRPCOperation objects with procedure path, input, and type
  5. Process Request — Links transform operations into network requests - httpBatchLink batches calls, adds headers, serializes data using configured transformers [TRPCOperation → HTTPRequest]
  6. Handle Server Request — resolveResponse parses HTTP requests, validates inputs against Zod schemas, executes procedure resolvers with context, and formats responses [HTTPRequest → HTTPResponse]
  7. Return Typed Result — Response is deserialized by client links, errors are wrapped in TRPCClientError with typed shapes, successful results maintain full type safety [HTTPResponse → TRPCClientError]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

Router packages/server/src/@trpc/server/index.ts
Record<string, Procedure | Router> with nested structure defining API endpoints and their input/output types
Created by combining procedures and sub-routers, compiled into type definitions, used by client for type inference
Procedure packages/server/src/@trpc/server/index.ts
Object with input schema (Zod), output type, middleware chain, and resolver function
Built using fluent API (.input().query()/.mutation()/.subscription()), validated against schema, executed with context
TRPCClientError packages/client/src/TRPCClientError.ts
Error class with message: string, shape: ErrorShape, data: ErrorData, meta: Record<string, unknown>
Created when API calls fail, contains typed error information from server, handled by error boundaries or catch blocks
TRPCLink packages/client/src/links/index.ts
Function that transforms Operation -> Observable<TRPCResponse> with terminating and non-terminating variants
Composed into chains for request processing, handles batching, caching, authentication, and transport
OpenAPIDocument packages/openapi/src/generate.ts
OpenAPI 3.1 spec object with paths, components, info metadata generated from tRPC router
Generated from tRPC router metadata, written to JSON file, used by documentation tools and REST API adapters

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

React Query Cache (cache)
Stores API response data with automatic background refetching, stale-while-revalidate patterns, and optimistic updates
Router Registry (registry)
Maps procedure paths to their definitions, middleware chains, and resolver functions for request routing
Type Definitions (in-memory)
Generated TypeScript types that enable compile-time type checking and IntelliSense for API calls

Feedback Loops

Delays

Control Points

Technology Stack

TypeScript (runtime)
Provides the type inference system that enables end-to-end type safety without code generation
Zod (library)
Runtime schema validation and TypeScript type inference for procedure inputs and outputs
TanStack Query (library)
Powers React hooks integration with caching, background updates, and optimistic mutations
Superjson (serialization)
Default data transformer for handling complex JavaScript types (Date, RegExp, BigInt) over JSON
Vitest (testing)
Test framework for unit and integration testing across all packages
Turbo (build)
Monorepo build system for managing dependencies and parallel builds across 45 packages

Key Components

Package Structure

server (library)
Core server-side API framework for defining type-safe procedures, routers, and middleware
client (library)
Client library for calling tRPC APIs with full type safety and link-based request handling
react-query (library)
React hooks for tRPC APIs using TanStack Query for caching, background updates, and optimistic updates
next (library)
Next.js adapter for server-side rendering and API routes with tRPC
openapi (library)
Generates OpenAPI 3.1 documentation from tRPC routers and provides REST endpoint adapters
tanstack-react-query (library)
Next-generation React Query integration with improved performance and developer experience

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Library Repositories

Frequently Asked Questions

What is trpc used for?

Builds end-to-end type-safe APIs with client libraries for React, Next.js, and framework adapters trpc/trpc is a 8-component library written in TypeScript. Data flows through 7 distinct pipeline stages. The codebase contains 983 files.

How is trpc architected?

trpc is organized into 4 architecture layers: Core Runtime, Client Layer, Framework Integrations, Developer Tools. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through trpc?

Data moves through 7 stages: Define API Schema → Generate Client Types → Create Client Instance → Make Procedure Call → Process Request → .... The system follows a request-response pattern where clients make type-safe procedure calls that are validated, executed on the server, and return typed results. The flow starts with procedure definitions on the server, generates TypeScript types for the client, and enables end-to-end type safety through the entire API lifecycle. This pipeline design reflects a complex multi-stage processing system.

What technologies does trpc use?

The core stack includes TypeScript (Provides the type inference system that enables end-to-end type safety without code generation), Zod (Runtime schema validation and TypeScript type inference for procedure inputs and outputs), TanStack Query (Powers React hooks integration with caching, background updates, and optimistic mutations), Superjson (Default data transformer for handling complex JavaScript types (Date, RegExp, BigInt) over JSON), Vitest (Test framework for unit and integration testing across all packages), Turbo (Monorepo build system for managing dependencies and parallel builds across 45 packages). A focused set of dependencies that keeps the build manageable.

What system dynamics does trpc have?

trpc exhibits 3 data pools (React Query Cache, Router Registry), 3 feedback loops, 4 control points, 3 delays. The feedback loops handle cache-invalidation and retry. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does trpc use?

4 design patterns detected: Type-safe RPC, Link Pattern, Proxy Pattern, Framework Adapter Pattern.

Analyzed on April 20, 2026 by CodeSea. Written by .