REST vs GraphQL vs gRPC: Choosing an API Style
A decision guide for the three dominant API paradigms — what each optimizes for, where each hurts, and how to choose.
There is no "best" API style — there are trade-offs, and a style that's right for a public developer platform is wrong for an internal microservice mesh. This guide gives you the mental model to choose, not a verdict to memorize.
REST: resources and HTTP verbs
REST models your system as resources identified by URLs, manipulated with HTTP verbs: GET /users/42, POST /users, DELETE /users/42. It leans entirely on HTTP — status codes, caching headers, content negotiation — which is its greatest strength.
REST shines when:
- Your API is public or consumed by many unknown clients. Everyone understands it; every tool supports it.
- Responses are cacheable. HTTP caching is free and powerful, and REST is built to use it.
- Resources map cleanly to nouns.
REST hurts when:
- Clients need different shapes of the same data. A mobile screen wants three fields; a dashboard wants thirty. REST tends toward either over-fetching (one fat endpoint) or under-fetching (many round trips), and the classic symptom is the N+1 request problem: fetch a list, then fetch each item's details one by one.
- Relationships are deep.
GET /users/42thenGET /users/42/poststhen a request per post's comments adds up fast.
GraphQL: the client describes the response
GraphQL exposes a single endpoint and a type system. The client sends a query describing exactly the fields it wants, across relationships, in one request:
query {
user(id: 42) {
name
posts(last: 3) { title comments { count } }
}
}
The server returns precisely that shape — no more, no less.
GraphQL shines when:
- You have many diverse clients (web, iOS, Android) evolving at different speeds and wanting different data. They self-serve without new backend endpoints.
- Data is a graph of relationships that clients traverse in varied ways.
- You want a strongly-typed contract and great tooling (introspection, generated clients).
GraphQL hurts when:
- You need HTTP caching. Because everything is a
POSTto one URL, you lose the free CDN/browser caching REST gives you, and must rebuild caching at the application layer. - Security and performance need per-query guarding. A single malicious query can ask for a deeply nested graph and melt your database; you need query depth/complexity limits and careful resolver design (the N+1 problem moves into your resolvers and is solved with batching, e.g. DataLoader).
- The API is small and stable — then GraphQL's machinery is overhead you don't need.
gRPC: contract-first RPC for services
gRPC is Remote Procedure Call done well: you define services and messages in a .proto file, and a compiler generates strongly-typed client and server code in many languages. It runs over HTTP/2 and serializes with Protocol Buffers — a compact binary format.
gRPC shines when:
- It's service-to-service, internal, and performance-sensitive. Binary serialization and HTTP/2 multiplexing make it fast and cheap.
- You want a single source of truth for the contract that generates code on both sides, eliminating drift.
- You need streaming — gRPC supports bidirectional streams natively.
gRPC hurts when:
- The client is a browser. gRPC isn't natively callable from browser JavaScript without a proxy (gRPC-Web), so it's awkward for public web APIs.
- Human debuggability matters. Binary payloads aren't
curl-friendly the way JSON is.
How to actually choose
Ask three questions in order:
- Who calls it? Browser or third-party public clients → REST or GraphQL. Internal services → strongly consider gRPC.
- How varied are the data needs? One shape fits all → REST. Many clients wanting many shapes → GraphQL.
- What's your scarcest resource? If it's network round trips and client flexibility, GraphQL pays off. If it's server CPU and latency between services, gRPC. If it's team time and operational simplicity, REST almost always wins.
A common, healthy architecture uses all three: REST or GraphQL at the edge for clients, gRPC between internal services. These aren't rival religions; they're tools at different layers.
You can move on when you can take a concrete feature — say, "a mobile app showing a user's feed" — and argue for a specific choice citing caching, client diversity, and round-trip cost, rather than naming a favorite.