gRPC
gRPC is a high-performance RPC (remote procedure call) framework, originally from Google, for service-to-service communication. You define services and messages once in a .proto file, and gRPC generates type-safe clients and server stubs in a dozen languages — calls between services look like local function calls.
Where REST models resources over JSON and HTTP semantics, gRPC models operations over a compact binary protocol (Protocol Buffers on HTTP/2). In microservice backends with many internal calls, that buys you speed, streaming, and contracts the compiler enforces.
TL;DR
- The
.protofile is the contract: services, methods, and message types in one schema, versioned in git. - Code generation produces clients and server stubs — no hand-written HTTP calls, no drifting client SDKs.
- Protocol Buffers serialize to compact binary: smaller and faster to parse than JSON.
- Runs on HTTP/2: multiplexed streams, header compression, and four call types including bidirectional streaming.
- Best fit: internal service-to-service APIs. Browsers can't speak native gRPC — public web APIs usually stay REST/GraphQL, or use gRPC-Web/a gateway.
- Never reuse field numbers in Protobuf messages — that's the backward-compatibility contract.
Quick Example
The contract:
A Node.js server and client (generated types via @grpc/proto-loader):
Core Concepts
Protocol Buffers
Protobuf is the schema language and binary format underneath gRPC:
- Each field has a number (
name = 2) used on the wire instead of the field name — that's why payloads are small. - Fields are optional by default in proto3; unknown fields are ignored, which is what makes rolling upgrades safe.
- Schema evolution rules: add new fields with new numbers freely; never change a field's number or type; never reuse a deleted field's number (mark it
reserved).
The Four Call Types
Streaming rides on HTTP/2 multiplexing — many concurrent streams share one TCP connection, without the WebSocket-style protocol switch.
Status Codes and Errors
gRPC has its own status vocabulary, not HTTP codes:
Richer error detail travels in google.rpc.Status metadata. Map these deliberately at any REST gateway (e.g. NOT_FOUND → 404, UNAVAILABLE → 503).
Deadlines and Metadata
Every call should carry a deadline — the client's absolute cutoff, propagated automatically to downstream calls:
Metadata (key-value pairs, like headers) carries auth tokens, trace context for distributed tracing, and request IDs.
gRPC vs REST vs GraphQL
The pragmatic pattern in many backends: gRPC inside, REST/GraphQL at the edge — internal services talk gRPC for speed and contracts, while a gateway (or grpc-gateway generating REST from your protos) serves browsers and third parties.
Best Practices
Treat Protos as a Versioned Public Contract
- Keep
.protofiles in a shared repo (or a Buf registry) with code review. - Package names carry the version (
users.v1); breaking changes mean a new package (users.v2), not edited fields. - Run a breaking-change linter (Buf) in CI.
Always Set Deadlines and Handle UNAVAILABLE
Network calls fail. Configure retries (idempotent methods only) with backoff, and treat DEADLINE_EXCEEDED/UNAVAILABLE as expected weather, not exceptional:
Secure It Like Any API
Use TLS between services (createInsecure() is for local dev only), pass identity in metadata (JWT or mTLS), and authorize per method — the same API security rules apply even on internal networks.
Mind the Load Balancer
gRPC holds long-lived HTTP/2 connections, so naive L4 load balancing pins all traffic from a client to one backend. Use L7/gRPC-aware load balancing (Envoy, Linkerd, cloud gRPC LBs) or client-side balancing in Kubernetes.
Common Mistakes
Reusing or Renumbering Protobuf Fields
Changing string email = 3 to string phone = 3 silently corrupts data for every client still sending the old field. Numbers are forever: add new ones, reserve old ones.
Exposing gRPC Directly to Browsers
Browsers can't make native gRPC calls (no control over HTTP/2 framing). Use gRPC-Web with an Envoy proxy, or put a REST/GraphQL gateway in front.
Using gRPC for a Public Third-Party API
Partners want curl, JSON, and OpenAPI docs. Unless your consumers are engineering teams who'll happily compile protos, expose REST publicly and keep gRPC internal.
No Deadline = Infinite Hang
A call without a deadline waits forever on a stuck server, tying up the connection pool. Set one on every call, even generous.
FAQ
Is gRPC faster than REST?
For service-to-service traffic, generally yes — binary Protobuf payloads are smaller and cheaper to parse than JSON, and HTTP/2 multiplexing cuts connection overhead. The gap matters most at high call volumes between microservices; for a low-traffic API the difference is negligible.
Can I use gRPC from a browser?
Not natively. gRPC-Web (through an Envoy or Connect proxy) covers unary and server-streaming calls. If browsers are your main client, REST or GraphQL is usually simpler.
What languages does gRPC support?
First-class codegen exists for Go, Java, Python, C#, C++, Node.js, Ruby, PHP, Kotlin, Swift, Dart, and Rust (via tonic) — one .proto generates consistent clients across all of them.
What is Buf?
The modern Protobuf toolchain: a linter, breaking-change detector, and schema registry that replaces hand-rolled protoc invocations. Widely considered table stakes for teams sharing protos.
gRPC or message queues for service communication?
Different tools: gRPC is synchronous request/response ("get me this user now"); message queues and Kafka are asynchronous ("this event happened, process whenever"). Most microservice systems use both.
Related Topics
- REST API Design — The default alternative at the public edge
- GraphQL — Client-driven query contracts
- Microservices — Where gRPC earns its keep
- Apache Kafka — Asynchronous event streaming counterpart
- Load Balancing — L7 balancing for long-lived HTTP/2
- Distributed Tracing — Propagating context through calls
- HTTP — The HTTP/2 foundation underneath