← All posts

REST, gRPC, GraphQL: When to Use Each (And Why Teams Pick Wrong)

The default answer to “what API protocol should we use?” has historically been REST. It remains the default. Most of the time, that’s fine. But “most of the time” isn’t all the time, and teams that keep picking REST out of habit pay taxes later.

Here’s a framework for actually choosing.

REST: Default for Understandable Reasons

What it is: HTTP verbs (GET, POST, PUT, DELETE) on predictable resource paths. /users/123, /posts/456/comments. Stateless. Cacheable. Firewall-friendly.

Why it dominates: HTTP is ubiquitous. Every load balancer, CDN, and proxy understands it. Caching lives for free at the edge. Your browser speaks it natively.

The cost:

Pick REST when:

Example: A public payment gateway API. Endpoint stability, caching behavior, and being firewall-friendly matter more than latency.


gRPC: Default When Speed and Volume Matter

What it is: Binary protocol (Protocol Buffers) over HTTP/2. Multiplexing. Streaming built-in. Statically typed schemas.

Why it wins for speed:

The cost:

Pick gRPC when:

Example: Payment processing pipeline where Order Service → Ledger Service → Analytics Service churn through millions of events per second. gRPC’s efficiency pays for the operational complexity.


GraphQL: Default When Clients Are Diverse and Complex

What it is: Strongly typed query language. Clients ask for exactly what they need. Server returns exactly that, nothing more, nothing less.

Why it wins for client flexibility:

The cost:

Pick GraphQL when:

Example: A content platform with web (desktop browsing, heavy pagination), mobile (minimal bandwidth, just summaries), and TV (rich media assets). Each client queries exactly what it needs. No more /users/profile-web-optimized endpoints.


Decision Matrix

Dimension REST gRPC GraphQL
Latency Medium (JSON overhead) Low (binary, multiplexing) Medium (depends on implementation)
Bandwidth High (JSON, overfetch) Low (binary, exact fields) Low (query projection)
Ease of Use High (HTTP, URLs, curl) Low (Protobuf, binary debugging) Medium (query language learning curve)
Caching Excellent (HTTP edge caching) Poor (binary, stateless, no proxies) Hard (POST queries, need client-side cache)
Real-time Bolted on (WebSockets) Built-in (streaming) Built-in (subscriptions)
Complexity Management Multiple versioned endpoints Single schema, protobuf versioning Single schema, backwards compatible
Browser-friendly Yes No (needs grpc-web) Yes
Multi-tenant isolation Simple (per-endpoint auth) Simple (per-stream context) Hard (query cost analysis)

The Hybrid Approach (Most Real Systems)

Most large systems use all three:

  1. REST for public APIs: Twilio, Stripe, AWS—everything external speaks REST because caching and HTTP ubiquity matter.

  2. gRPC for internal microservices: Payment service → order service → analytics. Speed and volume are constraints. Protobuf schemas are contracts.

  3. GraphQL for client-facing data aggregation: The web/mobile client talks to a GraphQL gateway that composes data from internal gRPC services. Clients get flexibility; the backend stays fast.

This is expensive to build (you’re maintaining 3 API surface layers). But it’s the cost of scale—each protocol solves a different constraint.


What Most Teams Get Wrong

  1. “We’ll start with REST and migrate to gRPC later.” No. The cost of migrating is high (schema changes, client updates, coordination). Pick early based on constraints, not convenience.

  2. “GraphQL will solve all our API problems.” It solves client flexibility. It creates new problems (query cost analysis, N+1 queries, caching). It’s not a pure win.

  3. “gRPC is faster, so we should use it for everything.” Speed matters if the network is the bottleneck. If your bottleneck is database latency, both are equally fine. You’re optimizing the wrong thing.

  4. “Public APIs should be GraphQL.” Public APIs should be REST (because caching and simplicity and HTTP ubiquity matter). GraphQL shines for internal/controlled clients.


The Honest Take

REST is safe. It’s the default for a reason. Use it unless you have a specific constraint (latency, bandwidth, client complexity) that it doesn’t solve.

gRPC wins when you control both ends and latency matters. If you’re building a distributed ledger backend or a payment processor, the efficiency gains pay for the complexity.

GraphQL wins when clients are diverse and control matters. If you’re building a platform with 5 different client types and slow iteration cycles, the query flexibility pays for the operational burden.

Most teams default to REST and regret it later (they wish they’d picked gRPC for internal services). Some teams pick GraphQL first and regret the caching complexity.

The smarter choice: pick based on constraints, not trends.

The honest reality: you’ll probably build all three before you’re done.