InterviewsVector
APIs & Communication· 8 min read· Updated August 29, 2026

REST vs gRPC vs GraphQL

Should my API use REST, gRPC, or GraphQL?

The verdict

Use REST for public, cacheable, resource-oriented APIs with broad client support. Use gRPC for low-latency, high-throughput internal service-to-service communication where both sides are yours. Use GraphQL when many different clients need to shape their own responses over a complex, connected graph and you want to eliminate over- and under-fetching. Most production systems mix them: gRPC between services, REST or GraphQL at the edge.

How to decide

YesNoYesNoYeselse
Start
Public or cacheable API for many clients?
REST
Low-latency internal service-to-service?
gRPC
Clients need to shape their own queries?
GraphQL
REST at the edge, gRPC internally
The decision at a glance — follow the branches to the right call.
  1. 1Who consumes it? Public/partners → REST or GraphQL. Your own services → gRPC.
  2. 2What are the latency and throughput needs on the hot path? Very high → gRPC.
  3. 3Do clients need to shape responses or avoid many round-trips over connected data? → GraphQL.
  4. 4How much do you rely on HTTP caching and CDNs? A lot → REST.
  5. 5Do you need streaming (server push, bidirectional)? → gRPC (or GraphQL subscriptions).
  6. 6It's rarely one answer: gRPC internally, REST/GraphQL at the edge is a common, defensible split.

The options

REST (HTTP + JSON)

Resources over HTTP verbs, human-readable JSON.

Best for

  • Public and partner APIs
  • Resource-oriented CRUD
  • Anything that benefits from HTTP caching and ubiquity

Strengths

  • Universal client support and tooling
  • Leverages HTTP caching, status codes, and CDNs directly
  • Simple to learn, debug, and document (OpenAPI)

Weaknesses

  • Over-fetching and under-fetching; often needs multiple round-trips
  • No enforced schema/contract unless you add one
  • Chatty for complex, nested data

gRPC (HTTP/2 + Protobuf)

Binary, contract-first RPC between services.

Best for

  • Internal microservice-to-microservice calls
  • Low-latency, high-throughput paths
  • Polyglot backends needing a strict shared contract

Strengths

  • Compact binary payloads and HTTP/2 multiplexing — low latency
  • Strong, versioned contracts via Protobuf; codegen in many languages
  • First-class bidirectional streaming

Weaknesses

  • Not natively callable from browsers (needs gRPC-Web + a proxy)
  • Binary payloads are harder to debug by hand
  • HTTP caching doesn't apply the way it does for REST

GraphQL

A typed query language; clients ask for exactly what they need.

Best for

  • Many client types (web, iOS, Android) with different data needs
  • Complex, connected data where fixed endpoints multiply
  • Aggregating several backends behind one graph

Strengths

  • Clients request exactly the fields they need — no over/under-fetching
  • One request can traverse a graph that would take many REST calls
  • Strong typed schema and introspection

Weaknesses

  • HTTP caching is hard (usually POST to one endpoint)
  • N+1 resolver problems and expensive/abusive queries need guarding
  • More server complexity; a real learning curve

Trade-offs at a glance

DimensionREST (HTTP + JSON)gRPC (HTTP/2 + Protobuf)GraphQL
TransportHTTP/1.1+HTTP/2HTTP (usually POST)
PayloadJSON (text)Protobuf (binary)JSON
PerformanceGoodBest (binary, multiplexed)Good; depends on resolvers
HTTP cachingNative, easyNot reallyHard
Client flexibilityFixed endpointsFixed methodsClient shapes the query
StreamingLimited (SSE/WebSocket)First-class bidirectionalSubscriptions
Browser-nativeYesNo (needs proxy)Yes
Best consumerPublic / cacheableInternal servicesMany varied clients

In the interview

During the API-design portion of a system-design interview, or directly as 'how would you expose this service?' The interviewer is checking whether you match the protocol to the consumer and the constraints.

What a Staff answer includes

A Staff answer matches protocol to consumer, latency, and caching — and names the operational cost of each: gRPC isn't browser-native without a proxy, GraphQL needs query-depth/cost limits and a caching strategy, REST over-fetches. It's comfortable proposing a mix rather than a single winner.

Follow-ups you should expect

  • How do you version each of these without breaking existing clients?
  • How do you cache a GraphQL API effectively?
  • How do you protect a GraphQL endpoint from expensive or malicious queries?
  • You picked gRPC internally — how does a browser client reach it?

Common mistakes

  • Reaching for GraphQL everywhere, then fighting HTTP caching and query-cost attacks.
  • Exposing gRPC directly to browsers instead of a gateway.
  • Ignoring schema evolution and backward compatibility (Protobuf field numbers, additive changes).
  • N+1 queries in GraphQL resolvers because there's no batching/dataloader.

Further reading

Related decisions