tRPC vs GraphQL
A comparison of tRPC, the TypeScript-native way to build fully type-safe APIs without a separate schema language, and GraphQL, the schema-driven query language for building flexible, client-specified APIs.
Quick Answer
tRPC gives full end-to-end type safety directly from TypeScript function signatures with zero code generation or schema language, but only works within a single TypeScript codebase (client and server); GraphQL works across any language or client, with a formal schema and mature caching/tooling ecosystem, at the cost of more setup complexity than tRPC's minimal-ceremony approach.
Reviewed by TechLogHub Engineering Team. Last updated September 26, 2026. Reflects tRPC's continued growth as the default choice for full-stack TypeScript monorepos in 2026, alongside GraphQL's continued relevance for multi-language or public-facing APIs.
| Feature | tRPC | GraphQL |
|---|---|---|
| Type Safety Approach | Automatic inference from TypeScript function signatures | Schema-driven, typically requires code generation for client types |
| Schema Language | None — plain TypeScript | GraphQL Schema Definition Language (SDL) |
| Code Generation Required | None required | Typically used (GraphQL Code Generator) for client type safety |
| Cross-Language Support | No — TypeScript client and server only | Yes — any language can be a client or server |
| Public API Suitability | Not designed for public/external consumption | Well-suited, formal schema as API contract |
| Caching/Tooling Ecosystem | React Query integration for client-side caching | Mature ecosystem (Apollo, Relay, various gateways) |
tRPC
A TypeScript library for building fully type-safe APIs where the client automatically infers types directly from server-side function signatures, with no schema language, code generation step, or separate API contract to maintain.
Pros
- End-to-end type safety with zero code generation — the client automatically infers exact types from server function signatures
- No separate schema language to learn or maintain — it's just TypeScript functions, using types you already know how to write
- Extremely fast iteration — changing a server function's signature immediately surfaces type errors on the client with no build step
- Minimal setup ceremony compared to GraphQL's schema, resolvers, and query language
- Excellent fit for full-stack TypeScript monorepos (Next.js, T3 stack) where both client and server share the same codebase
Cons
- Only works within a single TypeScript codebase — client and server must both be TypeScript, ruling it out for cross-language APIs
- Not designed for public, third-party-consumed APIs — there's no formal schema or documentation contract for external consumers
- Smaller ecosystem of caching, tooling, and gateway infrastructure compared to GraphQL's much more mature surrounding tooling
- Less established for very large-scale API surfaces spanning many independent teams or services compared to GraphQL's federation patterns
Best For
Full-stack TypeScript applications where the same team controls both client and server, particularly monorepo setups like the T3 stack, where type safety and iteration speed matter more than cross-language or public API support.
GraphQL
A schema-driven query language and runtime for building APIs that any client, in any programming language, can consume by specifying exactly the data they need against a formal, strongly-typed schema.
Pros
- Language-agnostic — any client in any programming language can consume a GraphQL API, unlike tRPC's TypeScript-only constraint
- Formal schema serves as a documented, versioned API contract suitable for public or third-party consumption
- Mature, extensive tooling ecosystem for caching (Apollo Client), federation across multiple services, and API gateways
- Well-established patterns for scaling API surfaces across many independent teams via schema federation
- Not tied to any specific backend language — GraphQL servers exist for virtually every major programming language
Cons
- More setup ceremony than tRPC — designing a schema, writing resolvers, and configuring the GraphQL server takes more upfront work
- Type safety between client and server isn't automatic the way tRPC's inference is — typically requires a code generation step (GraphQL Code Generator) to derive TypeScript types from the schema
- Steeper learning curve given its own query language and schema-first thinking, compared to tRPC's 'just write TypeScript functions' simplicity
- For a single-team, single-language TypeScript application, GraphQL's cross-language flexibility is often unused overhead
Best For
APIs that need to be consumed across multiple languages or by third-party/public clients, larger organizations needing to federate an API surface across many independent teams, and any context where GraphQL's mature ecosystem tooling outweighs its extra setup complexity.
The Core Trade-off: Constraint for Simplicity
tRPC's central insight is that if you're already writing both the client and server in TypeScript within the same codebase, you don't need a separate schema language or code generation step at all — the TypeScript compiler itself can verify that the client is calling server functions correctly, with real-time type inference. This constraint (same-language, same-codebase) is exactly why tRPC can offer a simpler, more immediate developer experience than GraphQL, which is deliberately designed to work across language and codebase boundaries and therefore needs a formal schema as the shared contract.
When the Cross-Language Constraint Actually Matters
tRPC's TypeScript-only requirement is a hard constraint, not a minor inconvenience — if your API needs to be consumed by a mobile app written in Swift or Kotlin, a third-party integration partner, or any client not written in TypeScript, tRPC simply isn't an option. GraphQL's schema-first design means the same API can serve a TypeScript web client, a native mobile app, and external partners consistently, which is precisely the scenario where its additional setup complexity becomes clearly worth the investment.
Type Safety: Automatic vs Generated
tRPC's type safety is genuinely automatic — there's no build or generation step; changing a server function's return type immediately shows a TypeScript error on any client code using it, since the types are inferred directly and live. GraphQL typically achieves client-side type safety through a separate code generation step (tools like GraphQL Code Generator) that reads the schema and produces TypeScript types, which works well but introduces a build step and a moment of potential staleness between schema changes and regenerated types that tRPC's live inference avoids entirely.
Ecosystem Maturity Favors GraphQL at Larger Scale
GraphQL's much longer establishment has produced a mature ecosystem of caching solutions (Apollo Client's normalized cache), federation patterns for splitting a schema across many independent backend services owned by different teams, and API gateway tooling. tRPC's simpler model doesn't need most of this machinery for its target use case (single-team, single-codebase TypeScript apps), but that also means it doesn't offer comparable solutions if a project's needs grow beyond that scope — organizations anticipating significant API surface growth across many teams often find GraphQL's established federation patterns a better long-term fit.
Verdict
Choose tRPC for full-stack TypeScript applications where the same team owns both client and server, especially monorepo setups — its automatic end-to-end type safety with zero code generation is a genuinely superior developer experience for that specific, common scenario. Choose GraphQL when your API needs to be consumed across multiple languages, by third-party or public clients, or needs to scale across many independent teams via schema federation — capabilities tRPC deliberately doesn't attempt to provide.


