When services talk to each other thousands of times per request inside a datacenter, the verbosity of JSON-over-HTTP/1.1 becomes a real tax. gRPC is Google's answer: a high-performance, contract-first RPC framework built on Protocol Buffers (a compact binary format) and HTTP/2. It's the third member of the API trio alongside REST and GraphQL — and where it shines is exactly where they don't: low-latency, high-throughput, polyglot service-to-service communication. It builds directly on the encoding ideas in our DDIA notes on encoding & evolution and complements our GraphQL vs REST comparison.

⚡ Quick Takeaways
  • Contract-first RPC — you define services and messages in a .proto file and generate strongly-typed client + server stubs in many languages.
  • Protocol Buffers — a compact, schema'd binary format; far smaller and faster to parse than JSON, with built-in schema evolution.
  • Built on HTTP/2 — multiplexing, binary framing, and header compression; the foundation for streaming.
  • Four call types — unary, server-streaming, client-streaming, and bidirectional streaming.
  • Best for internal microservices — low latency, high throughput, strict contracts, polyglot teams.
  • Weak for public/browser APIs — not human-readable, and browsers need a grpc-web proxy; REST/GraphQL still win at the public edge.
tldr

gRPC is a contract-first RPC framework: define your API in a .proto file, generate typed stubs, and call remote methods like local functions. It serializes with Protocol Buffers (compact binary) over HTTP/2, giving low latency, small payloads, and four streaming modes. It's excellent for internal, performance-sensitive, polyglot service-to-service communication, and a poor fit for public APIs or direct browser calls (where REST/GraphQL and human-readable JSON win).

What gRPC Is

gRPC is an RPC (Remote Procedure Call) framework: the goal is to make calling a method on a remote service feel like calling a local function. It's contract-first — you start by writing an interface definition (the .proto) describing the service's methods and message types, then a compiler generates client and server stubs in your languages. The client calls a generated method; the stub handles serialization, the network, and deserialization. (The classic caveat from DDIA still holds: a remote call isn't really like a local one — it can fail or time out — so design for partial failure.)

Protocol Buffers

The payload format is Protocol Buffers (protobuf) — a schema-based binary encoding. You declare typed messages with numbered fields; the encoded bytes carry the field tags, not names, making them compact and fast to parse, with well-defined rules for evolving the schema (add fields with new tags, never reuse a tag).

user.proto — the contract
service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListReq) returns (stream User);  // server streaming
}
message User {
  string id    = 1;
  string name  = 2;
  int64  since = 3;
}

From this one file, protoc generates a typed client and server in Go, Java, Python, etc. — the contract is the single source of truth, and both sides are guaranteed to agree on the wire format. Compared to JSON, protobuf is markedly smaller and faster to encode/decode, which is the bulk of gRPC's performance win.

Built on HTTP/2

gRPC runs over HTTP/2, and that choice unlocks most of its capabilities beyond protobuf:

The Four Call Types

Because HTTP/2 supports streams in both directions, gRPC offers four method shapes — a real advantage over request/response REST:

four RPC patterns
unary            client → 1 req     | 1 resp ← server     (normal call)
server-streaming client → 1 req     | many resp ← server  (feed/results)
client-streaming client → many req  | 1 resp ← server     (upload/aggregate)
bidirectional    client ↔ many      | many ↔ server       (chat, realtime)

Unary is the everyday request/response. The streaming modes shine for large result sets (server-streaming), uploads/telemetry (client-streaming), and interactive, low-latency exchanges (bidirectional) — use cases that are awkward over plain REST.

Code Generation and Contract-First Development

The workflow flips the usual REST habit of writing endpoints then documenting them. With gRPC the .proto is the API: you design it first, generate stubs for every service, and the compiler enforces that callers and implementers match. The benefits are type safety across language boundaries (a Go service and a Python client share one contract), no hand-written serialization, and the schema doubling as living documentation. The cost is a build step and a shared .proto to version and distribute.

gRPC vs REST vs GraphQL

AspectgRPCRESTGraphQL
PayloadProtobuf (binary)JSON (text)JSON (text)
TransportHTTP/2HTTP/1.1 or 2HTTP
ContractStrict (.proto)Loose (OpenAPI optional)Strict (schema)
StreamingFirst-class (4 modes)No (one req/resp)Subscriptions
BrowserNeeds grpc-web proxyNativeNative
Sweet spotInternal microservicesPublic/simple APIsFlexible client queries

When to Use gRPC (and When Not To)

Reach for gRPC for internal, performance-sensitive, service-to-service communication — especially in a polyglot microservices system where strict contracts and small, fast payloads matter, or when you need streaming. It's a common choice for the east-west traffic behind an API gateway, which often translates external REST to internal gRPC. Avoid it for public APIs (where consumers expect human-readable JSON and easy curl-ability) and for direct browser calls (browsers can't speak raw gRPC, so you need a grpc-web proxy). A frequent architecture: REST/GraphQL at the public edge, gRPC between services internally.

Limitations and Pitfalls

takeaway

gRPC = Protocol Buffers (compact binary, schema'd, evolvable) + HTTP/2 (multiplexed, streaming) + contract-first codegen. That combination makes it fast, strongly typed across languages, and great for internal microservice traffic and streaming — while its binary, non-browser-native nature keeps REST/GraphQL on top for public and frontend-facing APIs. The pragmatic pattern is REST at the edge, gRPC inside.

🎯 interview hot-takes

What is gRPC? A contract-first RPC framework using Protocol Buffers over HTTP/2, with generated typed stubs so a remote call looks like a local method.
Why is it faster than REST/JSON? Protobuf is compact binary (tags not field names) and quick to parse, and HTTP/2 multiplexes many calls over one connection with header compression.
What are the four call types? Unary, server-streaming, client-streaming, and bidirectional streaming — enabled by HTTP/2 streams.
When NOT to use gRPC? Public APIs (want human-readable JSON) and direct browser calls (need a grpc-web proxy); use REST/GraphQL there.
How does it relate to protobuf schema evolution? Add fields with new tag numbers, never reuse or renumber tags — giving backward/forward compatibility (see encoding & evolution).

← previous
API Gateway & Service Mesh