GraphQL & gRPC
TL;DR
GraphQL lets the client ask for exactly the data it needs (solving REST's over/under-fetching). gRPC uses a compact binary format for fast service-to-service communication. Both are tools for specific problems — not replacements for REST.
Two Problems, Two Tools
REST is great for most things. But as systems get more complex, two friction points keep showing up:
- The frontend keeps needing different slices of data → GraphQL
- Backend services need to talk to each other really fast → gRPC
Let's look at each.
GraphQL: "Just Give Me What I Need"
The Problem It Solves
Imagine you're building a mobile app. The profile screen needs to show a user's name, their 5 most recent posts, and the groups they belong to.
With REST, you'd need three API calls:
GET /users/42 → full user object (you only need name + avatar)
GET /users/42/posts → all posts (you only need the 5 most recent titles)
GET /users/42/groups → all groups (you only need names)

That's under-fetching — you need multiple round trips to get everything for one screen. On a slow mobile connection, each round trip hurts.
Now imagine the backend tries to help by creating a mega-endpoint that returns everything. Problem: it returns way too much data, most of which the screen doesn't need. Different screens need different subsets. You end up with either bloated responses or dozens of custom endpoints.

That's over-fetching. Neither option is great.
How GraphQL Fixes This
GraphQL (created by Facebook, open-sourced in 2015) flips the model. Instead of the server deciding what data to return, the client specifies exactly what it needs:
One request. One response. Only the fields you asked for. The server returns data shaped exactly like your query. No wasted data, no extra round trips.
When GraphQL Makes Sense
- Mobile apps with slow connections where minimizing data transfer matters
- Multiple frontend teams (web, mobile, TV app) that all need different slices of the same data
- Rapidly changing UI requirements where the frontend team doesn't want to wait for backend changes every time they need a different data shape
When It's Overkill
For most system design discussions, GraphQL adds complexity without clear benefit. You have a fixed set of requirements (not a moving target), and the interviewer usually wants to see how you optimize specific queries — GraphQL can get in the way of that conversation.
Use GraphQL in a design when the problem is explicitly about data flexibility or multiple client types needing different data shapes. Otherwise, REST is simpler and sufficient.
The Catch
GraphQL isn't magic. The server still needs to fetch all that data from databases. Under the hood, resolving a complex GraphQL query might involve the same database calls and custom code you'd write for REST endpoints. The complexity doesn't disappear — it just moves from the API surface to the resolver layer.
Advanced Deep Dive: The N+1 Query Problem
GraphQL fixes over-fetching on the frontend, but it can create a severe problem on the backend: the N+1 query trap. Consider our profile query — it fetches a user and their 5 posts. The GraphQL resolver for
userhits the database once (1 query). Then the resolver forpostsruns per user — if you're fetching a list of 50 users, that's 1 query for the user list + 50 individual queries for each user's posts = 51 database queries for one API call.At scale, this destroys database performance. The standard fix is a tool called DataLoader (created by Facebook alongside GraphQL). DataLoader batches those 50 individual
getPostsByUserIdcalls into a singleSELECT * FROM posts WHERE user_id IN (...)query. Without it, a deeply nested GraphQL query can silently generate hundreds of database round trips.The takeaway: GraphQL moves complexity from the API surface to the resolver layer — and if you're not careful, it multiplies database load rather than reducing it. In an interview, mentioning this trade-off (and DataLoader as the mitigation) shows you understand both sides of the GraphQL coin.
gRPC: "Talk Fast, Talk Small"
The Problem It Solves
REST uses JSON — human-readable text. That's great for debugging and public APIs. But when two backend services are talking to each other millions of times per second, JSON has two downsides:
- It's verbose — field names are repeated in every message
- It's slow to parse — text parsing is CPU-intensive compared to binary
How gRPC Fixes This
gRPC (created by Google) replaces JSON with Protocol Buffers — a compact binary format. You define your data structure once in a .proto file:
The same user in JSON:
→ about 40 bytesIn Protocol Buffers:
→ about 15 bytesLess data, and the binary format is much faster for computers to read and write.
gRPC also lets you define entire services:
This gets compiled into client and server code in whatever language you're using (Go, Python, Java, etc.). The client calls GetUser() like a normal function, and gRPC handles the networking, serialization, and type checking automatically.

When gRPC Makes Sense
- Internal service-to-service communication where performance matters
- High-throughput systems processing millions of requests per second
- When strong type safety between services is valuable (errors caught at compile time, not runtime)
When It Doesn't
gRPC is a binary protocol — web browsers can't natively speak it, and it's harder to debug (you can't just look at the data in a browser's network tab). For public-facing APIs that external developers will use, REST with JSON is still the standard.
A common pattern: REST for external APIs, gRPC for internal communication. Your public API speaks REST/JSON for broad compatibility. Behind the scenes, your microservices talk to each other using gRPC for speed.
Quick Comparison
| REST | GraphQL | gRPC | |
|---|---|---|---|
| Data format | JSON (text) | JSON (text) | Protocol Buffers (binary) |
| Style | "Here are my endpoints" | "Ask for what you need" | "Call this function" |
| Flexibility | Fixed response per endpoint | Client defines the shape | Fixed schema |
| Performance | Good | Depends on query | Excellent |
| Browser support | Yes | Yes | Limited |
| Best for | Public APIs, general use | Complex frontends, multi-client | Internal microservices |
| Complexity | Low | Medium | Medium |
The Decision
Start with REST. It's the default that everyone understands.
Consider GraphQL when: the interviewer emphasizes flexible data requirements, multiple client types, or mobile bandwidth constraints.
Consider gRPC when: the interviewer pushes on internal service communication performance, or when latency between services is a bottleneck.
Don't optimize your API protocol before you've addressed bigger problems in the design. The difference between REST and gRPC doesn't matter if your database is the bottleneck.
Interview Tip
Saying "REST for external, gRPC for internal" is a clean, defensible default. If asked to justify it: "REST is universally understood and easy for external consumers. gRPC gives us type safety and binary encoding for high-throughput internal calls." Simple.