gRPC is Google's RPC implementation: typed, fast, multi-language service-to-service calls over HTTP/2 with Protobuf binary serialization. It works in three steps:
- Write a
.protofile — define your messages and service methods once. This is the contract: language-agnostic and source-controlled. - Run
protoc— the compiler reads the.protoand generates typed client and server stubs in any language: Go, Java, Python, Node, Rust. - Call it like a function — your code calls the generated stub. It serializes arguments to binary, sends them over HTTP/2, and deserializes the response, transparently.
// What you write (any language — this is Go)
book, err := bookService.CheckoutBook(ctx, &pb.CheckoutRequest{ Id: 1 })
// → looks like a local function call
// → under the hood: Protobuf binary → HTTP/2 → server → Protobuf binary back Error handling is different
gRPC abstracts HTTP away completely. You never return an HTTP 404; instead, gRPC has its own set
of 16 standard status codes (NOT_FOUND, FAILED_PRECONDITION,
UNAVAILABLE) that the generated stubs surface as errors in your language.
// Server-side: signal failure with a gRPC status code, not an HTTP one
checkoutBook: (call, callback) => {
const book = books.find((b) => b.id === call.request.id);
if (!book?.available) {
return callback({ code: grpc.status.FAILED_PRECONDITION, message: "Not available" });
}
book.available = false;
callback(null, book);
}, Built-in streaming
Streaming is a first-class primitive in the contract, not a bolt-on:
| Mode | Flow | Use case |
|---|---|---|
| Unary | 1 req → 1 res | Same as a REST call. The default. |
| Server streaming | 1 req → many res | Client asks once; server pushes a stream. Like SSE but typed and binary. |
| Client streaming | many req → 1 res | Client streams data (file chunks); server replies once. |
| Bidirectional | many req → many res | Both sides stream independently. Voice, games, live collaboration. |
When to use gRPC
Use it when…
- Internal microservices — same data center, high volume, performance matters. Google, Kubernetes, and Uber all use gRPC internally.
- Multi-language teams — one
.protogenerates typed stubs for every team's language. - You need streaming — IoT telemetry, video feeds, live analytics.
- You want strict contracts — a breaking change is a compile error, not a runtime surprise.
Skip it when…
- Public APIs (usually) — external developers expect REST + JSON. (Tools like gRPC-Gateway can translate a gRPC service into a REST API automatically.)
- Browser clients — browsers can't speak raw gRPC: JavaScript APIs like
fetchdon't expose HTTP trailers during streaming, which gRPC requires. You need a proxy layer like gRPC-Web or ConnectRPC. - Simple CRUD services — the
protoctoolchain overhead isn't worth it for a small service. - You need readable traffic — binary Protobuf is opaque to
curland browser DevTools.
Check your understanding
Check your understanding
In REST you return HTTP 404 when a resource isn't found. How do you signal the same failure in gRPC?
Check your understanding