Skip to content

gRPC Mechanics#

gRPC is an RPC framework that uses HTTP/2 as transport and Protocol Buffers as the wire format. You write .proto files; tooling generates client and server stubs in many languages.

gRPC client and server communication over HTTP/2 with generated stubs
Source: Wikimedia Commons. CC BY 4.0.
flowchart LR
  Proto[.proto file<br/>service + messages] -->|protoc| ClientStub[Generated client]
  Proto -->|protoc| ServerStub[Generated server]
  Client[App code] --> ClientStub
  ClientStub -->|HTTP/2 + protobuf| ServerStub
  ServerStub --> Server[App handler]

    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    class Client,Server service;
    class ClientStub,ServerStub edge;

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

Four call types: unary (one req, one resp), server-streaming, client-streaming, bidirectional streaming. The streaming flavours leverage HTTP/2 streams natively.

gRPC turns the network into a typed function-call boundary. The combination of HTTP/2 multiplexing + protobuf efficiency makes it the default for high-throughput service-to-service traffic.

The wire format#

syntax = "proto3";
package payments.v1;

service PaymentService {
  rpc Charge (ChargeRequest) returns (ChargeResponse);
  rpc StreamTransactions (TxFilter) returns (stream Transaction);
  rpc UploadEvents (stream Event) returns (UploadAck);
  rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}

message ChargeRequest {
  string customer_id = 1;
  int64 amount_cents = 2;
  string currency = 3;
}

protoc generates client/server code in 10+ languages. Wire format is compact binary; fields are identified by tag number, so renaming is safe.

Four call types#

flowchart TB
  subgraph Unary
    C1[Client] -->|req| S1[Server]
    S1 -->|resp| C1
  end
  subgraph SS[Server streaming]
    C2[Client] -->|req| S2[Server]
    S2 -->|resp1| C2
    S2 -->|resp2| C2
    S2 -->|...| C2
  end
  subgraph CS[Client streaming]
    C3[Client] -->|req1| S3[Server]
    C3 -->|req2| S3
    S3 -->|resp| C3
  end
  subgraph Bidi
    C4[Client] -->|req1| S4[Server]
    S4 -->|resp1| C4
    C4 -->|req2| S4
    S4 -->|resp2| C4
  end

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

Server streaming: log tailing, paginated feed without round trips. Client streaming: uploads with progressive validation. Bidirectional: chat, real-time market data.

HTTP/2 mapping#

gRPC HTTP/2
Method :path = /payments.v1.PaymentService/Charge
Headers Initial HEADERS frame
Request body DATA frames
Trailers (status) Final HEADERS frame (grpc-status, grpc-message)
Cancellation RST_STREAM
Streaming Multiple DATA frames before close

Trailers are gRPC's clever trick: HTTP status is always 200; the real outcome is in trailing headers, so streaming errors after partial data are representable.

Error model#

grpc-status: 0  OK
              3  INVALID_ARGUMENT
              4  DEADLINE_EXCEEDED
              5  NOT_FOUND
              7  PERMISSION_DENIED
              8  RESOURCE_EXHAUSTED
              13 INTERNAL
              14 UNAVAILABLE

Plus grpc-message (human-readable) and optional google.rpc.Status details for structured error payloads.

Deadlines and cancellation#

# client
stub.Charge(req, timeout=2.0)
# server
def Charge(self, req, ctx):
    if ctx.time_remaining() < 0.1:
        ctx.abort(grpc.StatusCode.DEADLINE_EXCEEDED, "no time")

Deadlines propagate through chained RPCs; if upstream gave you 500ms and you've spent 200ms, your downstream RPCs see 300ms. Critical for tail-latency control.

Interceptors (middleware)#

class AuthInterceptor(grpc.ServerInterceptor):
    def intercept_service(self, continuation, handler_call_details):
        if not valid_token(handler_call_details.invocation_metadata):
            ...
        return continuation(handler_call_details)

Used for auth, logging, tracing, retries, rate limiting. Same shape as HTTP middleware.

Load balancing#

flowchart TB
  C[Client] --> Resolver
  Resolver --> List[Backend list]
  C --> LB[gRPC-LB policy<br/>pick_first / round_robin / xDS]
  LB --> B1[Backend 1]
  LB --> B2[Backend 2]
  LB --> B3[Backend 3]

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;

gRPC clients are smart: they connect to multiple backends directly and pick per-RPC, sidestepping the sticky-connection problem of L4 LB + HTTP/2. Policies:

  • pick_first: connect to first available; simple.
  • round_robin: spread across all healthy backends.
  • xDS / Envoy: Istio-style dynamic config.

For mesh, sidecars handle this. For direct LB, use headless services (Kubernetes), DNS SRV records, or a service registry.

Retries#

gRPC supports retries declaratively in the service config:

{
  "methodConfig": [{
    "name": [{"service": "payments.v1.PaymentService"}],
    "retryPolicy": {
      "maxAttempts": 3,
      "initialBackoff": "0.1s",
      "maxBackoff": "1s",
      "backoffMultiplier": 2.0,
      "retryableStatusCodes": ["UNAVAILABLE"]
    }
  }]
}

Only retry idempotent calls (annotate or test). Combine with deadlines; budget shouldn't be consumed by retries past the deadline.

When to choose gRPC#

  • Internal service-to-service.
  • High throughput, low latency.
  • Polyglot stack with shared schema.
  • Streaming endpoints natural to the domain.

When to skip gRPC#

  • Public-facing APIs (REST/GraphQL is more browser-friendly).
  • Web clients (grpc-web is OK but limited).
  • Simple CRUD endpoints (REST is fine and faster to debug).

Where gRPC connects#

flowchart TB
  GR((gRPC))
  H2[HTTP/2 deep dive<br/>required transport]
  HTTP[HTTP protocols<br/>compared with REST]
  REST[REST API design<br/>alternative style]
  GW[API Gateway<br/>REST↔gRPC translator]
  H2 --> GR
  HTTP -. compared with .-> GR
  REST -. alternative .- GR
  GR --> GW

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class GR service;
    class H2,HTTP,REST,GW datastore;

Glossary & fundamentals#

Tag Concept What it is Page
HLD HTTP2 deep dive the transport http2-deep-dive
HLD HTTP protocols comparison overview http-protocols
HLD API Gateway gRPC behind an API gateway api-gateway
LLD REST API design the major alternative rest-api-design

Quick reference#

Transport#

HTTP/2 + protobuf binary.

Call types#

Type Use
Unary Default RPC
Server-stream Tail logs, paginated feeds
Client-stream Resumable uploads
Bidi-stream Chat, market data

HTTP/2 mapping#

  • :path = /<package>.<service>/<method>
  • Body: protobuf in DATA frames
  • Status: trailers (HTTP 200 always)
  • Cancel: RST_STREAM

Status codes#

0 OK · 3 INVALID_ARGUMENT · 4 DEADLINE_EXCEEDED · 5 NOT_FOUND · 7 PERMISSION_DENIED · 8 RESOURCE_EXHAUSTED · 13 INTERNAL · 14 UNAVAILABLE

Deadlines#

Propagate through chains; subtract elapsed time.

Interceptors#

Auth, logging, tracing, retries, rate limit.

LB policies#

pick_first, round_robin, xDS. Clients balance per-RPC, not per-connection.

Retries#

Service config JSON; retry only idempotent calls; budget must fit in deadline.

When to use#

  • Internal service-to-service
  • Polyglot stacks
  • Streaming workloads
  • High throughput

When to skip#

  • Browsers (use grpc-web with caveats)
  • Public APIs
  • Simple CRUD

Refs#

  • grpc.io docs
  • protobuf.dev
  • gRPC over HTTP/2 spec

FAQ#

What is gRPC?#

gRPC is an RPC framework using HTTP/2 as transport and Protocol Buffers as the wire format. You define services in .proto files and generate clients and servers in many languages.

What is the difference between gRPC and REST?#

gRPC uses binary protobuf over HTTP/2 with code-generated stubs and typed contracts. REST uses JSON over HTTP/1.1 or HTTP/2 and is human-readable but less efficient.

What are the four call types in gRPC?#

Unary (one request, one response), server-streaming, client-streaming, and bidirectional streaming. Streaming flavours ride directly on HTTP/2 streams.

When should I choose gRPC over REST?#

Pick gRPC for high-throughput service-to-service traffic, strong typing, and streaming. Stick with REST for browser-facing APIs or simple integrations with many clients.

Does gRPC work in the browser?#

Browsers cannot speak raw HTTP/2 gRPC. Use gRPC-Web with a proxy like Envoy that translates between browser-friendly HTTP and native gRPC.

Further reading#