gRPC is Google's RPC framework built on two things that give it most of its advantages over REST: Protocol Buffers as the interface definition and serialization format, and HTTP/2 as the transport. Instead of writing an OpenAPI spec that describes a REST API after the fact, you write a .proto file that defines services and messages up front, and the compiler generates client and server code in whatever languages you need — the contract exists before either side is implemented, and it's enforced by the compiler, not by hoping everyone read the docs.
The .proto file is the contract
A service in gRPC is defined as a set of RPC methods with typed request and response messages, and the message fields are numbered, not named-in-JSON — those field numbers are what make the wire format compact and what make additive schema evolution safe (a new field with a new number doesn't disturb existing consumers reading old fields by number). The protoc compiler, or buf in most modern toolchains, turns this into strongly typed client stubs and server interfaces in Go, Java, Python, C#, TypeScript, and more, so the client and server are never out of sync about what a method accepts and returns.
syntax = "proto3";
package orders.v1;
service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
rpc ListOrders (ListOrdersRequest) returns (stream Order);
}
message GetOrderRequest {
string order_id = 1;
}
message Order {
string id = 1;
string status = 2;
int64 total_cents = 3;
}
Binary encoding over JSON, and why it matters
Protobuf serializes to a compact binary format rather than JSON's human-readable text, which means smaller payloads and faster serialize/deserialize on both ends — meaningful at scale, in service-to-service traffic where the same handful of message types cross the wire millions of times a day. The trade-off is that you can't just curl an endpoint and read the response; you need the .proto definition (or a tool like grpcurl) to make sense of the bytes. That's a real cost for debuggability and is one reason gRPC is far more common on internal service-to-service links than on public-facing APIs.
Four RPC types, not just request/response
Because gRPC runs over HTTP/2, it isn't limited to a single request producing a single response the way REST effectively is. A method can be unary (one request, one response — the REST-equivalent case), server-streaming (one request, a stream of responses — useful for a large result set or a live feed), client-streaming (a stream of requests, one response — useful for uploading a large or ongoing dataset), or bidirectional streaming (both sides stream independently over the same connection — useful for something like a chat session or live collaboration). Each is declared explicitly in the .proto with the stream keyword, so the contract states up front which shape a method has.
HTTP/2 multiplexes many concurrent RPCs over a single TCP connection instead of opening a new connection per request the way HTTP/1.1 effectively does. That's why gRPC connections tend to be long-lived — reconnecting per-call throws away the multiplexing advantage that makes gRPC fast in the first place.
gRPC status codes, not HTTP status codes
A gRPC response carries a gRPC status code — OK, NOT_FOUND, INVALID_ARGUMENT, UNAVAILABLE, DEADLINE_EXCEEDED, and so on — which is a different, purpose-built set from HTTP status codes, even though gRPC happens to run over HTTP/2 under the hood. Client libraries surface these as typed errors rather than something you parse out of an HTTP response, which matters when deciding what to do with a failure: UNAVAILABLE is usually safe to retry, INVALID_ARGUMENT is not.
When gRPC is the wrong choice
gRPC is a poor fit for anything a browser calls directly — browsers can't originate true HTTP/2 trailers-based gRPC calls without a proxy layer like gRPC-Web, and public APIs consumed by third parties benefit far more from REST's ubiquity, curl-ability, and native browser support. Reach for gRPC on internal, service-to-service traffic where both ends are under your control and performance or strict typing genuinely matters, and reach for REST (or GraphQL) at the edge where humans and browsers are involved.
Wrapping up
gRPC's value is the compiler-enforced contract, the compact binary wire format, and native support for streaming beyond simple request/response — all of which pay off most clearly in internal service-to-service communication. It costs you human-readability on the wire and browser compatibility at the edge, which is exactly why most systems that use it keep it behind a gateway that speaks REST or GraphQL to the outside world.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.