SproutStackSproutStack home

REST vs gRPC vs GraphQL

9 min readBeginner-friendlyFree to read

Read a little, play a little. No scary maths, and no rush.

Share:

Last reviewed: October 2026 · report an issue

The one-line verdict

  • Public APIs and simple CRUD? REST: resources at URLs, standard HTTP, understood by every tool.
  • Fast, typed calls between your own services? gRPC: Protocol Buffers contracts, generated code, streaming.
  • Many clients that each need different shapes of data? GraphQL: one endpoint where the client asks for exactly the fields it needs.

Each is a reasonable default in its own situation, and many companies use all three: REST for partners, gRPC inside the backend, GraphQL in front of their apps.

Three styles, three ideas

REST comes from Roy Fielding's 2000 dissertation. It describes an architectural style built from constraints such as client-server separation, stateless requests, cacheable responses and a uniform interface. In practice, that means resources at URLs (/orders/42) manipulated with HTTP methods (GET, POST, PUT, DELETE) and described by status codes.

gRPC treats the API as functions you call. You define services and messages in Protocol Buffers, the default interface definition language, and tooling generates client and server code in many languages. It runs over HTTP/2.

GraphQL gives clients one endpoint and a typed schema. The client sends a query describing exactly which fields it wants, and the response mirrors that shape.

Side by side

REST gRPC GraphQL
Shape Resources at URLs Methods on services One endpoint, typed schema
Data format Usually JSON Protocol Buffers (binary) JSON responses
Contract Optional (e.g. OpenAPI) Required .proto file Required schema
HTTP caching Natural, with GET per URL Not via standard HTTP caches Needs GET or persisted queries
Streaming Not built in (use SSE or WebSockets) Built in, four call types Subscriptions, implementation-dependent
Browsers Native Needs gRPC-Web and a proxy Native
Best fit Public APIs, CRUD Service-to-service Many client apps with varied needs

REST: the web's native shape

GET /products/42 HTTP/1.1
Accept: application/json

REST reuses everything the web already has. URLs identify resources; GET is safe to repeat and cacheable, so browsers and CDNs can store responses; status codes like 404 and 429 carry meaning every developer knows. Anyone can try an endpoint with curl.

The common pain points are overfetching (the endpoint returns more fields than this screen needs) and underfetching (a screen needs product, reviews and seller, so it makes three calls). On a slow mobile network, those extra round trips add up.

gRPC: calls that feel local

syntax = "proto3";

service Pricing {
  rpc GetPrice (PriceRequest) returns (PriceReply);
  rpc WatchPrices (WatchRequest) returns (stream PriceReply);
}

message PriceRequest { string product_id = 1; }
message PriceReply   { string product_id = 1; int64 price_paise = 2; }

From this file, tools generate a typed client and server stub in each language you use. Messages travel as compact binary Protocol Buffers over HTTP/2, and gRPC supports four kinds of methods:

  • Unary: one request, one response.
  • Server streaming: one request, a stream of responses (like WatchPrices above).
  • Client streaming: a stream of requests, one response.
  • Bidirectional streaming: both sides stream at once.

Clients can also set a deadline: how long they're willing to wait for a call before giving up, which is essential in chains of services.

The trade-offs: browsers can't call gRPC natively, so you'd use gRPC-Web with a proxy such as Envoy, and binary messages are harder to inspect by eye than JSON.

GraphQL: ask for exactly what you need

query ProductPage {
  product(id: "42") {
    name
    price
    seller { name rating }
    reviews(first: 3) { stars text }
  }
}

One request returns product, seller and reviews, with only those fields. That's why GraphQL is popular in front of mobile and web apps with many different screens.

The flexibility moves work to the server, and the GraphQL project's own performance guide names the three things to plan for:

  • The N+1 problem: fetching a list, then one extra lookup per item. The usual fix is batching with a tool like DataLoader.
  • Caching: queries are often sent with POST, which HTTP caches skip. Using GET for queries, or persisted queries (sending a hash instead of the full query), restores CDN-friendly caching.
  • Demand control: a client could ask for a huge, deeply nested query. Paginate list fields, limit depth and breadth, and analyze query complexity.

A worked example: one shopping platform

  • Partner API for logistics companies to fetch orders: REST. Every partner can call it from any language, and GET /orders/42 caches cleanly.
  • Pricing service called by checkout, search and recommendations thousands of times a second: gRPC, with typed contracts, generated clients, deadlines, and streaming price updates.
  • Mobile app backend serving product pages, carts and profiles: GraphQL, so each screen fetches exactly its fields in one round trip, with DataLoader and complexity limits in place.

Five questions that decide it

  1. Who calls the API? Outside developers favor REST; your own services favor gRPC; your own apps with many screens favor GraphQL.
  2. Do browsers call it directly? REST and GraphQL work natively; gRPC needs gRPC-Web and a proxy.
  3. How much does caching matter? REST gets HTTP caching for free; the others need deliberate setup.
  4. Do you need streaming? gRPC has it built in.
  5. What can your team operate well? A well-run REST API beats a poorly-run GraphQL server.

Honest limits

  • Performance claims vary wildly. Payload size, network and implementation matter more than the style's name. Measure before choosing on speed alone.
  • None of these is "REST" or "GraphQL" by label alone. Many "REST" APIs ignore caching and status codes, and many GraphQL servers ship without query limits.
  • Switching later is expensive once clients depend on an API, so choose by who your callers are, not by trend.

Remember this

  • REST = resources at URLs, cacheable, universal.
  • gRPC = typed function calls over HTTP/2, best between services.
  • GraphQL = clients pick their fields; plan for N+1, caching and query limits.
  • Mixing them by audience is common and sensible.

Check your understanding

5 questions · first-try answers earn the most XP

1. Your internal pricing service is called thousands of times a second by other backend services, and you want typed contracts with generated client code. Which style fits best?
2. Your browser app needs to call a gRPC service directly. What do you usually need?
3. A GraphQL query for 50 users and each user's latest order triggers 51 database queries. What is this called, and what is the usual fix?
4. Why is HTTP caching usually simpler with a REST API than with GraphQL?
5. You are opening an API to outside partners who use many different languages and tools. Which choice is usually the safest default?

My notes

Saved in this browser. Highlight a line above and save it, or write it in your own words.

Nothing saved yet. Your highlights will live here.

References

Finished reading?

Ticking it here also ticks the chapter in the sidebar, the section count and your streak — it is all one number.

Related chapters

Spotted a mistake or want a topic covered? Report an issue

📬 An occasional email when new lessons land

New lessons and showdowns, no more than a few times a month. No spam, unsubscribe anytime. We store your email only to send the newsletter.