Backend · Guide

GraphQL & gRPC

The two common answers to "REST is not the right shape here" — and what each one costs.

— min read Backend

When REST Stops Fitting

REST is the right default. The two situations where it strains are a client that needs many related things at once, and a service-to-service call where HTTP and JSON are pure overhead. GraphQL answers the first; gRPC answers the second.
RESTGraphQLgRPC
ShapeResourcesOne typed graphTyped procedure calls
Wire formatJSONJSONBinary protobuf
Best forPublic APIsVaried client needsInternal service-to-service
Browser supportNativeNativeNeeds a proxy
CachingHTTP, for freeApplication-level workApplication-level work

GraphQL

GraphQL exposes one endpoint and a typed schema. The client states exactly what it wants and receives that shape — which ends both over-fetching and the round-trip chains REST clients build.

type Query { order(id: ID!): Order }

type Order {
  id: ID!
  total: Int!
  customer: Customer!      # the client decides whether to fetch this
  lines: [OrderLine!]!
}

# one request, exactly the fields this screen needs
query { order(id: "42") { total customer { name } } }
BuysCosts
No over- or under-fetchingHTTP caching no longer applies
One request for a whole screenQuery cost is now your problem
A strongly typed, introspectable schemaReal server-side complexity
Clients evolve without server changesErrors arrive inside a 200
The N+1 problem is the defining GraphQL bug: a query for 50 orders calls the customer resolver 50 times, one query each. DataLoader-style batching — collect the ids in a tick, fetch them in one query — is not optional at any real scale.

A public GraphQL endpoint also needs depth and cost limits. Nothing stops a client requesting friends-of-friends-of-friends and asking your database to do a week of work in one request.

gRPC

gRPC is remote procedure calls over HTTP/2 with protocol buffers: you define the service and messages in a .proto file, generate typed client and server code for every language you use, and send compact binary frames.

syntax = "proto3";

service Orders {
  rpc GetOrder (GetOrderRequest) returns (Order);
  rpc WatchOrders (WatchRequest) returns (stream Order);   // server streaming
}

message GetOrderRequest { string id = 1; }

message Order {
  string id       = 1;      // field numbers are the wire contract —
  int64  total    = 2;      // never reuse or renumber them
  string customer = 3;
}
StrengthCost
Compact and fast — binary, multiplexedNot human-readable; needs tooling to debug
Generated clients in every languageA build step and a shared proto repository
Streaming in both directionsBrowsers need grpc-web and a proxy
Schema-first by constructionField numbering discipline forever
Field numbers, not names, are the wire format. Renaming a field is harmless; reusing a retired number silently reinterprets old data as something else — which is why retired numbers are reserved, never recycled.

Choosing Between Them

SituationReach for
A public API for third partiesREST — everyone can call it with curl
Many clients wanting different slicesGraphQL
Mobile on a poor connectionGraphQL — one round trip, minimal payload
Internal services, high volumegRPC
Streaming updates between servicesgRPC
Anything a browser calls directlyREST or GraphQL

Mixing them is normal and often correct: REST at the public edge, gRPC between internal services, GraphQL in a gateway that fans out to both. The failure is adopting one because it is fashionable and inheriting problems the previous shape did not have.

Interview Questions

What does GraphQL solve that REST does not?

Over- and under-fetching. One request returns exactly the fields a screen needs, instead of several round trips or a fixed payload with unused data.

What is the N+1 problem in GraphQL?

A list resolver runs a nested resolver once per item, issuing one query each. Batching with a DataLoader — collecting ids within a tick and fetching them together — is the standard fix.

What does GraphQL cost you?

HTTP caching stops applying, query cost becomes your responsibility, errors arrive inside 200 responses, and the server gets substantially more complex.

Why is gRPC faster than REST over JSON?

Binary protobuf payloads are much smaller than JSON, and HTTP/2 multiplexes many calls over one connection with header compression.

Why do protobuf field numbers matter?

They are the wire contract. Renaming a field is safe; reusing a retired number makes old data decode as something else entirely, so retired numbers are reserved permanently.

When would you not use gRPC?

For anything a browser calls directly — it needs grpc-web and a proxy — and for public APIs, where third parties expect to call you with ordinary HTTP tools.

Quick Quiz

1. The N+1 problem in GraphQL is fixed by…
2. GraphQL loses which REST advantage?
3. gRPC sends payloads as…
4. Reusing a retired protobuf field number…
5. For a public third-party API, prefer…