gRPC
In a Nutshell
gRPC is a high-performance framework for service-to-service communication built by Google. Instead of sending JSON over HTTP like REST, it uses Protocol Buffers (a compact binary format) over HTTP/2, and you define your API as a set of typed service methods in a .proto file — actual function calls, not resource URLs. From that contract, gRPC generates strongly-typed client and server code in many languages. The result is fast, efficient, strongly-typed remote procedure calls with built-in streaming. gRPC shines for internal microservice communication where performance and strong contracts matter more than the human-readability and browser-friendliness that make REST dominant at the public edge.

How It Actually Works
Contract-First with Protocol Buffers
You define the service and messages in a .proto file — the single source of truth:
syntax = "proto3";
service OrderService {
rpc GetOrder(GetOrderRequest) returns (Order);
rpc ListOrders(ListOrdersRequest) returns (stream Order); // server streaming
}
message GetOrderRequest { string order_id = 1; }
message Order {
string id = 1;
double total = 2;
repeated Item items = 3;
}
From this, gRPC generates client and server stubs in Go, Java, Python, etc. The client calls GetOrder() as if it were a local function; gRPC handles serialization, transport, and deserialization. The typed contract means breaking changes are caught at compile time.
Why It's Fast
| Feature | Benefit |
|---|---|
| Protocol Buffers (binary) | Much smaller + faster to serialize than JSON text |
| HTTP/2 | Multiplexing, header compression, persistent connections |
| Streaming | Native bidirectional streaming over one connection |
| Code generation | No hand-written serialization; strongly typed |
REST/JSON: {"id":"42","total":19.5} → ~verbose text, parse overhead
gRPC/Protobuf: 0x0A 02 34 32 11 ... → compact binary, tiny + fast
Four Call Types (Streaming Is Native)
| Type | Shape | Use |
|---|---|---|
| Unary | 1 request → 1 response | Normal RPC |
| Server streaming | 1 request → stream of responses | Live feed, large result sets |
| Client streaming | Stream of requests → 1 response | Uploads, telemetry batches |
| Bidirectional streaming | Stream ↔ stream | Chat, real-time sync |
Streaming is first-class in gRPC (via HTTP/2), unlike REST where it's awkward.
gRPC vs REST vs GraphQL
| Aspect | REST | GraphQL | gRPC |
|---|---|---|---|
| Format | JSON (text) | JSON (text) | Protobuf (binary) |
| Transport | HTTP/1.1+ | HTTP | HTTP/2 |
| Contract | Loose (OpenAPI optional) | Schema | Strict .proto |
| Performance | Good | Good | Excellent |
| Browser support | Native | Native | Limited (needs gRPC-Web proxy) |
| Streaming | Awkward | Subscriptions | Native, all directions |
| Human-readable | Yes | Yes | No (binary) |
| Best for | Public/web APIs | Flexible client data | Internal microservices |
The Browser Problem
gRPC's main limitation: browsers can't speak gRPC directly (no raw HTTP/2 frame access from JS). You need a gRPC-Web proxy to translate. This is why gRPC dominates internal east-west communication but rarely faces the public web directly — where REST/GraphQL remain the norm.
When to Choose gRPC
Great fit:
✅ Internal microservice-to-microservice calls (performance matters)
✅ Low-latency, high-throughput systems
✅ Polyglot backends (generate clients in many languages)
✅ Streaming workloads (real-time, large datasets)
✅ Strict, versioned contracts across teams
Prefer REST/GraphQL when:
✅ Public-facing / browser-facing APIs
✅ Human-readability and easy debugging matter
✅ Broad third-party ecosystem / simple integration

Seeing It in Action
Scenario: Choosing gRPC for internal microservices, REST at the edge.
Architecture: a public API with many internal microservices behind it.
Public edge (browser + mobile + third parties):
→ REST / GraphQL via an API gateway.
Human-readable, browser-native, cache-friendly, easy to integrate.
Internal service-to-service (east-west):
→ gRPC.
order-service → inventory-service.GetStock(product_id)
order-service → pricing-service.CalculatePrice(cart)
Each is a typed function call over HTTP/2 with binary Protobuf.
Why gRPC internally:
✅ Performance: binary Protobuf + HTTP/2 multiplexing → lower latency
and CPU than JSON, which compounds across millions of internal calls.
✅ Strong contracts: the .proto is the shared source of truth. If
inventory-service changes a field, order-service fails to COMPILE
rather than breaking mysteriously at runtime.
✅ Polyglot: inventory (Go), pricing (Java), order (Python) all generate
native clients from the same .proto — no hand-written HTTP clients.
✅ Streaming: a real-time stock feed uses server streaming natively.
Why NOT gRPC at the edge:
✗ Browsers can't speak gRPC without a gRPC-Web proxy.
✗ Third-party developers expect REST/JSON; binary is hard to debug.
The pattern that emerges: use the right protocol for each traffic type. gRPC's speed, strong typing, and streaming make it ideal for the high-volume internal calls between services, where both ends are yours and performance compounds. REST/GraphQL's readability and universal client support make them ideal at the public edge, where humans, browsers, and third parties are involved. Many mature systems run exactly this split — REST/GraphQL north-south, gRPC east-west — because it optimizes each boundary for what actually matters there.
Interview Questions
Q: What makes gRPC faster than REST/JSON? Hint: It serializes with Protocol Buffers (compact binary, faster to encode/decode than verbose JSON text) and runs over HTTP/2 (multiplexing many calls on one connection, header compression, persistent connections). It also generates serialization code rather than parsing text. Across high-volume internal calls, the lower payload size and CPU cost compound significantly.
Q: What does "contract-first with Protocol Buffers" mean and why is it valuable? Hint: You define services and messages in a
.protofile, the single source of truth, and generate strongly-typed client/server code in many languages. Value: the contract is enforced at compile time — a breaking change makes callers fail to compile rather than break at runtime — and polyglot teams share one authoritative definition, eliminating hand-written, drift-prone HTTP clients.Q: Describe gRPC's four call types. Hint: Unary (1 request → 1 response, normal RPC), server streaming (1 request → stream of responses, e.g., live feed/large results), client streaming (stream of requests → 1 response, e.g., uploads/telemetry), and bidirectional streaming (both directions simultaneously, e.g., chat/real-time sync). Streaming is native via HTTP/2, unlike REST where it's awkward.
Q: Why is gRPC used mostly for internal services rather than public/browser APIs? Hint: Browsers can't speak gRPC directly (no raw HTTP/2 frame access from JS) — you need a gRPC-Web proxy. Its binary format isn't human-readable, making third-party integration and debugging harder. So gRPC dominates internal east-west service-to-service traffic (where both ends are yours and performance matters), while REST/GraphQL remain the norm at the public, browser-facing edge.
Q: How do you decide between REST, GraphQL, and gRPC? Hint: gRPC for internal microservice communication needing high performance, strong contracts, streaming, and polyglot clients. GraphQL for flexible, client-driven data needs with many clients and complex nested data. REST for simple, resource-oriented, cache-friendly, browser/third-party-facing public APIs. Many systems combine them: REST/GraphQL north-south at the edge, gRPC east-west internally.
References
- gRPC official documentation — concepts, streaming, code generation
- Protocol Buffers — the serialization format and IDL
- gRPC vs REST (Google Cloud) — when to use each
Dive Deeper
- gRPC-Web — bringing gRPC to browsers via a proxy
- Google API Design Guide — designing gRPC and REST APIs consistently
- HTTP/2 explained — the transport that makes gRPC fast