<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 https://www.facebook.com/tr?id=1063935717132479&amp;ev=PageView&amp;noscript=1 "> gRPC

gRPC

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:

  1. Write a .proto file — define your messages and service methods once. This is the contract: language-agnostic and source-controlled.
  2. Run protoc — the compiler reads the .proto and generates typed client and server stubs in any language: Go, Java, Python, Node, Rust.
  3. 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
.proto service BookService rpc GetBook(…) message Book {…} 1 schema protoc code generator Go stubs Python stubs Node stubs Java stubs typed client + server
One .proto contract feeds protoc, which generates typed client and server stubs for every language your teams use.

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:

ModeFlowUse case
Unary1 req → 1 resSame as a REST call. The default.
Server streaming1 req → many resClient asks once; server pushes a stream. Like SSE but typed and binary.
Client streamingmany req → 1 resClient streams data (file chunks); server replies once.
Bidirectionalmany req → many resBoth 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 .proto generates 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 fetch don't expose HTTP trailers during streaming, which gRPC requires. You need a proxy layer like gRPC-Web or ConnectRPC.
  • Simple CRUD services — the protoc toolchain overhead isn't worth it for a small service.
  • You need readable traffic — binary Protobuf is opaque to curl and 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

Why can't a web browser call a gRPC service directly?