Skip to main content

REST vs tRPC vs GraphQL vs gRPC: API Patterns 2026

·APIScout Team
Share:

The Death of REST? The Rise of Type-Safe API Patterns

REST isn't dead. But it's no longer the automatic default. In 2026, developers have real alternatives — tRPC for full-stack TypeScript, GraphQL for complex data requirements, gRPC for microservices, and new patterns that blur the line between API and function call. Here's when each makes sense.

The driver for this shift isn't performance (REST over HTTP/2 is fast). It's developer experience: specifically, type safety across the client-server boundary. A REST endpoint returning any in TypeScript provides no compile-time guarantees. When you rename a field on the server, the client breaks at runtime, not at build time. tRPC, GraphQL with codegen, and gRPC all solve this problem — at the cost of additional tooling, setup complexity, or reduced language flexibility.

The Contenders

REST (Representational State Transfer)

The standard since 2000. HTTP methods, URL paths, JSON responses.

// Server
app.get('/api/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id);
  res.json(user);
});

// Client
const res = await fetch('/api/users/123');
const user: User = await res.json(); // No type safety at boundary

Status in 2026: Still dominant for public APIs, third-party integrations, and polyglot architectures. Not going anywhere.

tRPC (TypeScript Remote Procedure Call)

End-to-end type safety between TypeScript client and server. No code generation.

// Server — define router
const appRouter = router({
  user: router({
    getById: publicProcedure
      .input(z.object({ id: z.string() }))
      .query(async ({ input }) => {
        return db.users.findById(input.id);
      }),

    create: publicProcedure
      .input(z.object({
        name: z.string(),
        email: z.string().email(),
      }))
      .mutation(async ({ input }) => {
        return db.users.create(input);
      }),
  }),
});

// Client — fully typed, autocomplete works
const user = await trpc.user.getById.query({ id: '123' });
// TypeScript knows user.name is string, user.email is string, etc.

Status in 2026: Standard for full-stack TypeScript apps (Next.js, Nuxt). Growing fast.

GraphQL

Query language for APIs. Client specifies exactly what data it needs.

# Client requests exactly what it needs
query {
  user(id: "123") {
    name
    email
    posts(first: 5) {
      title
      publishedAt
    }
  }
}
// Server — type-safe with codegen
import { useQuery } from '@apollo/client';
import { GetUserDocument } from './generated/graphql';

const { data } = useQuery(GetUserDocument, {
  variables: { id: '123' },
});
// data.user.name is typed via codegen

Status in 2026: Entrenched in companies that adopted it (Facebook, GitHub, Shopify). Growth has slowed. New projects often choose tRPC instead.

gRPC (Google Remote Procedure Call)

Binary protocol with Protocol Buffers for schema definition. Fastest serialization.

// user.proto — schema definition
service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc CreateUser (CreateUserRequest) returns (User);
}

message GetUserRequest {
  string id = 1;
}

message User {
  string id = 1;
  string name = 2;
  string email = 3;
}

Status in 2026: Standard for microservices communication. Growing in mobile (gRPC-Web). Not for browser-to-server.

Hono RPC / Server Actions

Emerging patterns that make API calls feel like function calls:

// Next.js Server Actions
'use server';
export async function createUser(formData: FormData) {
  const user = await db.users.create({
    name: formData.get('name') as string,
    email: formData.get('email') as string,
  });
  return user;
}

// Client — call server function directly
<form action={createUser}>
  <input name="name" />
  <input name="email" />
  <button>Create</button>
</form>

Status in 2026: React Server Actions are production-ready. Blurs the API boundary entirely.

Comparison Matrix

FeatureRESTtRPCGraphQLgRPC
Type safety❌ (manual)✅ (automatic)✅ (codegen)✅ (codegen)
Language agnostic❌ (TypeScript)
Browser support⚠️ (gRPC-Web)
Streaming⚠️ (SSE)✅ (subscriptions)✅ (native)
Caching✅ (HTTP cache)⚠️⚠️ (complex)
File uploads⚠️⚠️
Learning curveLowLow (if TS)HighHigh
EcosystemMassiveGrowingLargeLarge
Over-fetchingCommonNoNoNo
Code generation neededNoNoYesYes
Public API friendly

When to Use Each

Use REST When

  • Building a public API — REST is universally understood
  • Third-party integrations — partners expect REST
  • Polyglot team — not everyone uses TypeScript
  • Simple CRUD — REST maps perfectly to database operations
  • HTTP caching matters — REST leverages browser and CDN caching natively
  • Webhooks — REST is the standard for webhook delivery

Use tRPC When

  • Full-stack TypeScript — Next.js, Nuxt, SvelteKit
  • Internal APIs — no need for language-agnostic interface
  • Rapid development — zero config, instant type safety
  • Monorepo — client and server share types automatically
  • Small-to-medium teams — reduces boilerplate dramatically

Use GraphQL When

  • Complex data relationships — nested objects, multiple entity types
  • Multiple clients — mobile, web, third-party all need different data shapes
  • Existing investment — already using GraphQL, team knows it
  • Federation — multiple services merged into one API (Apollo Federation)
  • Real-time subscriptions — built-in subscription support

Use gRPC When

  • Microservices — service-to-service communication
  • Performance critical — binary serialization is 5-10x faster than JSON
  • Streaming — bidirectional streaming is first-class
  • Polyglot microservices — Go, Rust, Java, Python all generate clients from protobuf
  • Mobile — efficient binary protocol saves bandwidth

The "Death of REST" Is Exaggerated

The "REST is dead" narrative surfaces every few years, fueled by whoever has a new API paradigm to sell. It has never been accurate, and in 2026 it still isn't — though the nuance is real: REST is no longer the only reasonable choice for every scenario, which is different from being dead.

REST isn't dying because:

  1. Every API directory, every tool, every tutorial assumes REST — the ecosystem is unmatched
  2. HTTP caching is incredibly powerful — and REST gets it for free
  3. Simplicity scales — junior developers understand REST immediately
  4. curl works — you can test any REST API from a terminal
  5. Webhooks are REST — event-driven architecture uses REST endpoints

What IS happening:

  • Internal APIs are moving to tRPC (TypeScript projects) or gRPC (microservices)
  • GraphQL found its niche (complex data, multi-client) and stopped trying to replace everything
  • Server Actions may replace API routes for form submissions and mutations
  • Public APIs remain REST and will for the foreseeable future

The Real Trend: Type Safety Everywhere

The common thread across tRPC, GraphQL (with codegen), gRPC, and REST + OpenAPI is type safety. This isn't a new idea — strongly-typed RPC systems predate REST. What's new is that the tooling has reached a level of ergonomics where type safety doesn't require a 2-week setup and a dedicated platform team. tRPC works in an afternoon. OpenAPI + openapi-typescript is a one-time codegen setup. The barrier has dropped enough that "untyped API boundary" is now a deliberate architectural choice, not a default.

Developers in 2026 expect:

  1. Compile-time errors when API contracts change
  2. IDE autocomplete for API responses
  3. Automatic validation of request payloads
  4. Generated documentation from type definitions

REST can achieve this with OpenAPI + codegen, but it's bolted on. The newer patterns have it built in.

REST + OpenAPI: Type Safety Without Migration

Before choosing tRPC or GraphQL, consider whether REST + OpenAPI already solves your type safety problem. OpenAPI is a mature, widely-supported spec format that describes your REST API in a machine-readable way. Combined with code generation, it gives you client types that stay in sync with your server implementation.

The workflow: define your API schema in OpenAPI (or generate it from your server code), then generate TypeScript types for the client with openapi-typescript. The result is a typed fetch client that throws compile errors when the API contract changes.

// Generated by openapi-typescript from your OpenAPI spec
import type { paths } from './api.d.ts';
import createClient from 'openapi-fetch';

const client = createClient<paths>({ baseUrl: '/api' });

// Fully typed — TypeScript knows the exact response shape
const { data, error } = await client.GET('/users/{id}', {
  params: { path: { id: '123' } },
});
// data.name is typed as string, data.email is typed as string, etc.

This approach works with any language on the backend (not TypeScript-only like tRPC) and is compatible with all existing REST tooling. For teams with existing REST APIs, it's often the highest-value, lowest-effort path to end-to-end type safety.

Migrating an Existing REST API

For teams considering moving from REST to tRPC or GraphQL for an existing product, the practical advice is: don't migrate wholesale. The operational cost of rewriting working API endpoints is almost always higher than the DX benefit.

Instead, apply type safety incrementally:

  • Add OpenAPI to existing REST routes using Zod schemas: zod-to-openapi generates an OpenAPI spec from your existing Zod schemas, which you can use with openapi-typescript to generate fully typed client code. This gives you most of tRPC's type safety benefits without changing your API surface.
  • Use tRPC for new internal routes only. Don't rip out existing REST routes; add new capabilities via tRPC. Over time the codebase can migrate organically.
  • Consider a dual API: Shopify, GitHub, and others maintain both REST and GraphQL APIs. Maintaining two is more work, but it means existing integrations don't break and new integrations can use the better pattern.

The biggest migration trap is tRPC's TypeScript-only constraint. If you have any non-TypeScript clients (a mobile app using Swift or Kotlin, a partner using Python), tRPC won't work for those consumers. REST with OpenAPI-generated clients is the pragmatic choice for public or polyglot APIs.

Recommendation for New Projects (2026)

Project TypeRecommendedWhy
Full-stack Next.js apptRPCZero-config type safety
Public API productREST + OpenAPIUniversal adoption
Mobile + web + partnersGraphQL or RESTMultiple client support
Microservices (Go, Rust, Java)gRPCPerformance, polyglot
SaaS with third-party integrationsRESTPartners expect it
Real-time featurestRPC subscriptions or GraphQLBuilt-in support

Methodology

API usage data based on npm download statistics (March 2026), Stack Overflow Developer Survey results, and public engineering blog posts from teams that have publicly discussed their API architecture decisions. Benchmark data on gRPC vs REST serialization performance sourced from published benchmarks by Cloudflare and individual community benchmark projects. tRPC adoption figures sourced from npmjs.com weekly download data. GraphQL adoption data from the State of JavaScript 2025 survey.

Compare API patterns and find the right architecture for your project on APIScout — guides, comparisons, and real-world examples for REST, GraphQL, tRPC, and gRPC.

Related: Type-Safe APIs with TypeScript in 2026, How to Build a Type-Safe API Client with TypeScript, Building TypeScript API Client SDKs

The API Integration Checklist (Free PDF)

Step-by-step checklist: auth setup, rate limit handling, error codes, SDK evaluation, and pricing comparison for 50+ APIs. Used by 200+ developers.

Join 200+ developers. Unsubscribe in one click.