Pick GraphQL when many clients consume the API and each wants different fields. Pick tRPC when you control both ends in a TypeScript monorepo and want types to flow without a schema layer. If neither shape fits, REST is the default and gRPC is the choice for internal services — see our gRPC vs REST page for that side of the decision.
GraphQL
Schema-first query language. Clients ask for exactly the fields they need.
This is the modern API-protocol decision and it has four serious contenders: REST, GraphQL, tRPC, and gRPC. REST is the universal default for any audience that isn't you (covered on a separate page); gRPC is the binary-internal choice (also covered separately). The interesting modern choice for app developers is GraphQL vs tRPC — flexible client-driven queries vs zero-friction TypeScript types. Pick by what shape your client situation has.
Quick takes
If you're…
You're building a public API for many client types→GraphQLGraphQL lets each client pick its fields. Mobile, web, partners all share one schema.
You control both client and server in a TypeScript monorepo→tRPCtRPC is unmatched for DX in this case. Types flow from server to client with zero codegen.
You need a public API that third-party developers will integrate→GraphQLGraphQL has tooling (GraphiQL, Apollo Studio, schema introspection) for external consumers.
Your team only speaks TypeScript→tRPCtRPC is TS-only by design. If you ever need a non-TS client, you need OpenAPI or codegen.
You need real-time subscriptions→GraphQLGraphQL has Subscriptions built in. tRPC subscriptions exist but require WebSocket setup.
You're looking for HTTP semantics — caching, status codes, REST tooling→EitherNeither is HTTP-native. If HTTP semantics matter, look at REST first.
You need internal service-to-service calls at scale→EitherNeither is ideal here — gRPC is the canonical answer for this shape.
You want to ship product fast in an SSR full-stack app→tRPCtRPC + Next.js or SvelteKit removes a whole class of boilerplate.
A query language and a schema. Clients send queries to a single endpoint specifying exactly the fields they need; the server resolves and returns matching shape. One endpoint, many shapes.
tRPC
Typed RPC over HTTP. Server defines procedures (queries + mutations); clients call them like normal TypeScript functions. Types flow via TypeScript inference, no schema needed.
core
Type safety
edge: tRPC
GraphQL
Schema-first typing. SDL (Schema Definition Language) defines types; codegen (graphql-codegen) produces client types. Generated, not inferred — has to be re-run on schema change.
tRPC
TypeScript inference end-to-end. The client gets types from the server's implementation with no codegen step. Changes are reflected immediately. Only works if both ends are TS.
features
Over-fetching prevention
edge: GraphQL
GraphQL
Original design goal. Clients request exactly the fields needed; server returns only those. Massive bandwidth wins on mobile or low-bandwidth contexts.
tRPC
Each procedure returns its predefined shape. To get a subset, the server has to define a new procedure or the client has to call multiple. Less elegant for selective fetching.
core
Language support
edge: GraphQL
GraphQL
Servers and clients in any language. Apollo, urql, Relay for JS; gqlgen for Go; Graphene for Python; Hot Chocolate for .NET; Hasura / PostGraphile for instant Postgres APIs.
tRPC
TypeScript only. Server in TS, client in TS. Trying to consume a tRPC API from Python or Go means writing the request manually — no types, no inference.
ops
Tooling
edge: GraphQL
GraphQL
Mature ecosystem: GraphiQL, Apollo Studio, Hasura Console, GraphQL Yoga, Pothos. Schema explorer is universal. Excellent developer experience for external API consumers.
tRPC
Light by design. TanStack Query integration is the headline feature. No introspection UI, no schema browser — but also no schema to browse.
features
Real-time / subscriptions
edge: GraphQL
GraphQL
Subscriptions are first-class in the spec. graphql-ws transport is standard. WebSocket-based, with reconnection, multiplexing, and auth all defined.
tRPC
Subscriptions exist (since 10.x) using a WebSocket link or Server-Sent Events. Working but requires setup; not as polished as the GraphQL story.
ops
Setup complexity
edge: tRPC
GraphQL
High. Schema definition, resolvers, DataLoader for N+1, query depth limits, complexity analysis. Real ops surface — every Apollo Server outage post-mortem is a teachable moment.
tRPC
Low. `t.procedure.input(z.object({...})).query(({input}) => ...)`. That's the entire API. No schema files, no resolvers, no complexity analysis.
ecosystem
Adoption + community
edge: GraphQL
GraphQL
Used at Meta, Netflix, Airbnb, GitHub, Shopify. Huge installed base. Server-side caches (Apollo, Hasura) are production-grade. Has been in production for a decade.
tRPC
Used by smaller startups, Cal.com, Vercel's own work. Growing fast in the Next.js/SvelteKit ecosystem. About 5 years old. Not used at the biggest tech companies (because they aren't TS-only).
Benchmark
Request overhead, simple "get user" call
Identical Node.js server, 1 KB user payload, 100 concurrent clients via autocannon. GraphQL using Apollo Server 4, tRPC v10 with HTTP batched link, REST + gRPC for context.
Metric
GraphQL
tRPC
Better
p50 latency (GET-shaped)
tRPC has less per-request overhead.
3.8 ms
2.4 ms
tRPC
Bytes on wire (overfetched)
GraphQL wins when client picks 2 of 8 fields; tRPC returns all.
142 B
318 B
GraphQL
Bytes on wire (full object)
When client wants everything, tRPC's smaller protocol overhead wins.