📚 Learning Hub
· 6 min read
Last updated on

tRPC vs GraphQL — Which API Layer for TypeScript?


Opening

Choosing an API layer for a modern TypeScript project often comes down to two contenders: tRPC and GraphQL. Both move beyond REST by offering typed contracts between client and server, but they take fundamentally different approaches.

tRPC is purpose-built for TypeScript monorepos. If your frontend and backend share a single language and repository, tRPC lets you call server functions directly from the client with full type inference — no code generation, no schema files, no build step. It’s become the default choice in ecosystems like the T3 stack.

GraphQL is a schema-first query language designed for multi-client architectures. It shines when you have a web app, a mobile app, and third-party consumers all hitting the same API. The schema acts as a contract that any language can consume, making it ideal for public APIs and organizations with diverse tech stacks.

Comparison Table

FeaturetRPCGraphQL
Schema definitionNone — inferred from TypeScriptRequired SDL (Schema Definition Language)
Type safetyEnd-to-end, automaticRequires codegen tools
Language supportTypeScript onlyAny language
TransportHTTP / WebSocketHTTP / WebSocket
Learning curveLow (just write TypeScript)Moderate (SDL, resolvers, client libraries)
Code generationNot neededNeeded for typed clients
Client flexibilityFixed proceduresClients choose exact fields
SubscriptionsBuilt-in via WebSocketSupported via subscriptions spec
File uploadsStandard multipartRequires extra spec or library
CachingManual / React QueryNormalized cache (Apollo, Relay)
ToolingVS Code autocomplete, tRPC PanelGraphiQL, Apollo Studio, Voyager
Best fitMonorepos, Next.js, T3 stackPublic APIs, multi-client systems

Type Safety

This is where the philosophical difference is clearest.

tRPC provides end-to-end type safety from server to client without any intermediate step. You define a router with input/output validators (typically Zod), and the client automatically infers every type.

Change a return field on the server and your IDE immediately flags every broken call site. No codegen pipeline, no generated files, no drift between schema and implementation.

GraphQL achieves type safety through its schema, but bridging that to TypeScript requires code generation. Tools like GraphQL Code Generator parse your .graphql files and produce typed hooks or SDK functions.

The result is excellent — but it adds a build step, generated files, and potential staleness if the pipeline isn’t integrated into your workflow.

For a solo developer or small team in a single TypeScript repo, tRPC’s zero-config approach removes an entire category of friction. For larger organizations where the schema is shared across teams, GraphQL’s explicit contract is worth the extra tooling.

Schema Definition

tRPC has no schema file. Your router definitions are the schema, expressed as plain TypeScript. This means there’s nothing to learn beyond the language you already write. Refactoring is just renaming functions and updating validators.

The downside is that there’s no standalone artifact you can hand to a team that doesn’t have access to your TypeScript codebase — the “schema” only exists within the code itself.

GraphQL uses the Schema Definition Language (SDL) — a dedicated syntax for declaring types, queries, mutations, and subscriptions. The schema is language-agnostic, which is precisely why it works across ecosystems.

However, it introduces a layer of indirection: you write the schema, then implement resolvers that match it, then generate client types from it. The benefit is that the schema becomes documentation, a contract, and a validation layer all in one. Tools like GraphiQL and Apollo Studio can introspect it to provide API explorers automatically.

Both approaches are valid. tRPC optimizes for speed within TypeScript. GraphQL optimizes for interoperability and explicit contracts across teams and languages.

Client Flexibility

One of GraphQL’s defining features is that clients request exactly the fields they need — nothing more, nothing less. A mobile client can fetch a lightweight subset while a dashboard fetches the full object, all from the same endpoint.

Nested queries are another advantage. A single GraphQL request can traverse relationships — fetching a user, their posts, and each post’s comments — without multiple round trips.

tRPC procedures return fixed shapes. You can use input parameters to control what gets returned, but it’s not as elegant as GraphQL’s field selection. If you have multiple clients with different data needs, GraphQL scales better.

In a monorepo where you control both sides, over-fetching is rarely a problem — you shape the procedure to return what the page needs.

Ecosystem

GraphQL has a mature ecosystem built over nearly a decade of production use. Apollo Client, Relay, Urql, Hasura, Apollo Federation, schema stitching, persisted queries, normalized caching — the list is extensive.

The community has solved pagination (Connections spec), real-time updates, and API gateway patterns at scale. Tooling includes GraphiQL for interactive queries, Apollo Studio for schema management, and Voyager for visualization.

tRPC’s ecosystem is smaller but focused. It integrates tightly with TanStack Query, Next.js, Nuxt, SvelteKit, and the T3 stack. tRPC Panel gives you an API explorer similar to GraphiQL.

Adapters exist for Express, Fastify, AWS Lambda, and Cloudflare Workers. For TypeScript full-stack apps, the ecosystem covers everything you need.

If you need federation across microservices or a public developer portal with documentation, GraphQL’s ecosystem is far ahead. If you need a fast, simple setup for a Next.js app, tRPC’s focused tooling is more than sufficient.

When to Use Each

Choose tRPC when:

  • Your frontend and backend are both TypeScript
  • You’re working in a monorepo (Next.js, T3 stack, Turborepo)
  • Your API is consumed only by your own clients
  • You want the fastest possible developer experience with zero config
  • You value simplicity over flexibility
  • You’re prototyping and need to move fast
  • Your team is small and co-located

Choose GraphQL when:

  • You have multiple clients (web, mobile, third-party integrations)
  • You’re building a public API with external consumers
  • Your team uses multiple languages on the backend
  • Clients have very different data requirements
  • You need a schema as a shared contract between teams
  • You want normalized client-side caching
  • You need API federation across microservices

For RPC-style communication in non-TypeScript environments, gRPC is worth evaluating — especially for service-to-service calls where performance is critical.

Verdict

tRPC and GraphQL solve the same core problem — typed API communication — but for different contexts.

Pick tRPC for TypeScript monorepos where speed and simplicity matter most. You get end-to-end type safety with zero overhead. If you’re building a Next.js app with a co-located backend, tRPC feels like a natural extension of your codebase.

Pick GraphQL for multi-client architectures, public APIs, or teams spanning multiple languages. The schema-first design and client flexibility justify the additional tooling. If external developers consume your API, or if you serve different data shapes to different platforms, GraphQL pays dividends.

They aren’t mutually exclusive. Some teams use tRPC for internal services and expose a GraphQL gateway for external consumers. Use the right tool for the context.

FAQ

Is tRPC better than GraphQL?

For TypeScript monorepos where you control both client and server, tRPC is better — it provides end-to-end type safety with zero configuration or code generation. For multi-client architectures, public APIs, or polyglot teams, GraphQL’s schema-first approach and client flexibility make it the stronger choice.

Can I use tRPC without Next.js?

Yes. tRPC has adapters for Express, Fastify, AWS Lambda, Cloudflare Workers, and more. While it’s popular in the Next.js/T3 stack ecosystem, it works with any TypeScript backend framework.

Does tRPC work with non-TypeScript clients?

Not well. tRPC’s core value proposition is TypeScript type inference between client and server. Non-TypeScript clients can technically call tRPC endpoints via HTTP, but they lose all type safety benefits, making GraphQL or REST a better choice for polyglot consumers.

Is GraphQL dying?

No. GraphQL remains the standard for public APIs, multi-client architectures, and large organizations with diverse tech stacks. Its ecosystem continues to mature with tools like Apollo Federation and Relay. tRPC has taken share in the TypeScript monorepo niche, but GraphQL’s broader use cases remain strong.