OpenAPI vs tRPC vs GraphQL: Best API Architecture (2026)
API architecture affects every part of your application. The right choice depends on your team, your clients, and your scale. In 2026, three approaches dominate: OpenAPI (REST), tRPC, and GraphQL.
Quick Comparison
| Feature | OpenAPI (REST) | tRPC | GraphQL |
|---|---|---|---|
| Type safety | Generated from spec | End-to-end (automatic) | Generated from schema |
| Protocol | HTTP/REST | HTTP (RPC) | HTTP (single endpoint) |
| Schema | OpenAPI spec (YAML/JSON) | TypeScript types | GraphQL SDL |
| Over-fetching | Common | Depends on design | Solved (query what you need) |
| Under-fetching | Common (N+1 requests) | Depends on design | Solved (nested queries) |
| Caching | HTTP caching (excellent) | Custom | Complex (normalized cache) |
| Client generation | Yes (openapi-typescript) | Automatic (same codebase) | Yes (graphql-codegen) |
| Language support | Any | TypeScript only | Any |
| Learning curve | Low | Low (if you know TS) | Medium-High |
| Best for | Public APIs, multi-client | Full-stack TypeScript apps | Complex data, mobile apps |
OpenAPI (REST): The Universal Standard
REST with OpenAPI specification gives you a documented, standardized API that any client can consume.
Strengths
Universal compatibility. Any language, any platform can consume a REST API. curl, Python, Go, mobile SDKs — REST works everywhere.
HTTP caching. REST leverages HTTP's built-in caching (ETags, Cache-Control, CDN caching). This is free performance that GraphQL and tRPC have to build manually.
Tooling ecosystem. OpenAPI has the broadest tooling: Swagger UI for docs, client generators for 50+ languages, testing tools, API gateways, and monitoring.
Simplicity. GET, POST, PUT, DELETE — the mental model is simple and well-understood. Every developer knows REST.
Proven at scale. Stripe, Twilio, GitHub — the most successful APIs in the world are REST.
Weaknesses
Over-fetching and under-fetching. GET /users returns everything about every user. Need just names? Too bad. Need users AND their posts? That's two requests.
No built-in type safety. REST endpoints don't inherently provide TypeScript types. You need OpenAPI spec + code generation for type safety.
Versioning complexity. API versioning (v1, v2) is messy. Breaking changes require careful migration strategies.
Documentation maintenance. Keeping OpenAPI spec in sync with implementation requires discipline (or tools like tRPC that generate it).
Best For
Public APIs consumed by external developers. APIs serving clients in multiple languages. Microservices communication. Any API where HTTP caching matters significantly.
tRPC: End-to-End TypeScript
tRPC provides end-to-end type safety between your TypeScript backend and TypeScript frontend with zero code generation.
Strengths
Zero-API overhead. Define a function on the server, call it from the client with full type safety. No API spec, no code generation, no separate API layer.
// Server
export const appRouter = router({
getUser: publicProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
return db.user.findUnique({ where: { id: input.id } });
}),
});
// Client — fully typed, autocomplete works
const user = trpc.getUser.useQuery({ id: "123" });
// user is typed as the return type of getUser
Instant type feedback. Change the server function's return type → TypeScript errors appear in the client immediately. No build step, no regeneration.
React Query integration. tRPC wraps TanStack Query, giving you caching, prefetching, optimistic updates, and infinite queries for free.
Simple. No schema language to learn. No resolvers. No type generation. Just TypeScript functions.
Subscriptions. WebSocket subscriptions for real-time updates with the same type-safe DX.
Weaknesses
TypeScript only. Both server and client must be TypeScript. No Python, Go, Swift, or Kotlin clients.
Monorepo requirement. Server and client need to share types, which typically means a monorepo or shared package.
No public API story. tRPC isn't designed for public APIs consumed by external developers. No auto-generated documentation.
Tightly coupled. Frontend and backend are coupled through shared types. This is a feature AND a limitation.
No HTTP caching. tRPC uses POST for mutations and GET for queries, but doesn't leverage HTTP caching semantics as naturally as REST.
Best For
Full-stack TypeScript applications (Next.js, Remix, SvelteKit). Internal APIs. Startups and small teams moving fast. Any project where both client and server are TypeScript.
GraphQL: Query What You Need
GraphQL gives clients the power to request exactly the data they need in a single request.
Strengths
No over-fetching. Clients specify exactly which fields they need. A mobile client can request minimal data while a desktop client requests everything.
query {
user(id: "123") {
name
avatar
posts(limit: 5) {
title
createdAt
}
}
}
Single request for complex data. Nested relationships resolved in one round trip. No N+1 API calls.
Strong typing. GraphQL schema defines every type, field, and relationship. Code generation produces type-safe clients.
API evolution without versioning. Add fields without breaking existing clients. Deprecate fields gracefully. No v1/v2 versioning.
Introspection. Clients can query the schema itself — enabling auto-generated documentation, playground tools, and IDE extensions.
Weaknesses
Complexity. Schema design, resolvers, data loaders (for N+1 prevention), caching (normalized cache vs. document cache) — there's a lot to learn and maintain.
Performance gotchas. Naive implementations suffer from N+1 database queries. Requires DataLoader or similar batching. Deep queries can cause expensive joins.
Caching is hard. HTTP caching doesn't work well with GraphQL (everything is POST to one endpoint). Client-side normalized caching (Apollo, urql) is complex.
Error handling. GraphQL returns 200 OK even when errors occur (errors are in the response body). This confuses monitoring tools and makes error tracking harder.
Security surface. Query depth attacks, complex queries consuming server resources, and introspection exposure require careful configuration.
Best For
Mobile apps (where bandwidth matters and over-fetching is costly). Applications with complex, nested data relationships. APIs serving multiple clients with different data needs. Large teams where schema-first development adds value.
Real-World Decision Guide
Startup Building a SaaS (Full-Stack TypeScript)
Winner: tRPC. Maximum development speed. Zero API boilerplate. Type safety with no effort. Switch to REST/GraphQL when you need a public API.
Building a Public API
Winner: OpenAPI (REST). Universal compatibility. Self-documenting with Swagger. Every developer knows how to consume it.
Mobile App with Complex Data
Winner: GraphQL. Minimize bandwidth with precise queries. Handle offline with normalized caching (Apollo). Single endpoint simplifies mobile networking.
Microservices Communication
Winner: REST with OpenAPI. HTTP caching, universal language support, and proven patterns. Consider gRPC for high-performance service-to-service communication.
Team of 20+ Engineers
Winner: GraphQL. Schema-first development provides a contract between frontend and backend teams. Schema governance prevents API sprawl.
Can You Combine Them?
Yes. Common hybrid approaches:
tRPC + OpenAPI: Use tRPC for your internal frontend, generate an OpenAPI spec from tRPC routes for external consumers (trpc-openapi plugin).
REST + GraphQL: REST for simple CRUD, GraphQL for complex data queries. Many large companies use both.
tRPC + GraphQL: Rare but possible. tRPC for your web app, GraphQL for mobile clients that need flexible queries.
Performance Comparison
| Metric | REST | tRPC | GraphQL |
|---|---|---|---|
| Payload size | Often oversized | Right-sized | Exactly right |
| Number of requests | Multiple | Depends | Usually one |
| Caching | HTTP cache (excellent) | Custom | Complex |
| Latency (simple query) | ~Same | ~Same | ~Same |
| Latency (complex data) | N requests | Depends | 1 request |
For most applications, the performance differences are negligible. Architecture and developer experience matter more.
FAQ
Should I learn GraphQL in 2026?
Yes, but don't default to it. Understand it so you can make informed decisions. For most new projects, tRPC (TypeScript) or REST (multi-language) is simpler and sufficient.
Is REST dead?
No. REST is the most used API architecture and will be for years. It's simple, universal, and battle-tested. GraphQL and tRPC are alternatives for specific use cases, not replacements.
Can I switch from tRPC to REST later?
Yes. tRPC procedures map naturally to REST endpoints. The business logic stays the same; you add an HTTP layer on top. The trpc-openapi plugin can help with gradual migration.
Is GraphQL overkill for my project?
If your data model is simple (flat resources, minimal relationships) and you have one client (web), yes. GraphQL shines with complex, nested data and multiple clients with different needs.
The Verdict
- OpenAPI (REST) — The safe, universal choice. Public APIs, multi-language, microservices. Start here if unsure.
- tRPC — The fast, type-safe choice for full-stack TypeScript. Best DX for internal APIs. Start here for Next.js/Remix apps.
- GraphQL — The flexible choice for complex data. Mobile apps, multi-client, large teams. Worth the complexity when data relationships are complex.
For most startups building full-stack TypeScript apps in 2026: start with tRPC, add REST (via trpc-openapi) when you need a public API. This gives you maximum speed now with a clear migration path later.