Call
APIs

What Is gRPC? Protocol Buffers, HTTP/2, Streaming, Deadlines, and Generated APIs

gRPC is a typed remote-procedure-call framework built around service contracts, generated client/server code, Protocol Buffers by default, HTTP/2-based transport, unary and streaming RPCs, metadata, status codes, deadlines, cancellation, health checks, and secure channels.

Published: September 13, 2025
Updated: September 12, 2026
12 min read
What Is gRPC? Protocol Buffers, HTTP/2, Streaming, Deadlines, and Generated APIs

What Is gRPC? Protocol Buffers, HTTP/2, Streaming, Deadlines, and Generated APIs

gRPC is a framework for calling methods on another service over the network using a defined service contract rather than hand-building each HTTP endpoint and client.

You define services and message types, generate client/server code, implement the server methods, and call them through a generated client stub.

By default, gRPC uses Protocol Buffers for both its interface definition and serialized messages, and its standard transport is built around HTTP/2 semantics.

The simplest mental model

Imagine two backend services:

checkout service
      |
      | GetStock(product_id)
      v
inventory service

With gRPC, the shared contract can look like:

syntax = "proto3";

package inventory.v1;

service InventoryService {
  rpc GetStock(GetStockRequest) returns (GetStockResponse);
}

message GetStockRequest {
  string product_id = 1;
}

message GetStockResponse {
  int32 available = 1;
}

The service definition describes:

  • method name
  • request type
  • response type

The message definitions describe the structured data sent across the network.

.proto files are the contract

Protocol Buffer schemas live in .proto files.

A field has a name, type, and numeric field identifier:

message Product {
  string id = 1;
  string name = 2;
  int64 price_minor = 3;
}

The field number is part of the binary wire representation.

Once a field is deployed, its number must be treated as stable API history. If you remove a field, reserve the number so a future developer cannot accidentally reuse it for a different meaning.

The schema is source code and should be reviewed and versioned like any other public/internal API contract.

Code generation removes repetitive client plumbing

The Protocol Buffer compiler and gRPC plugins generate code for supported languages.

On the server side, generated code gives you an interface/base type to implement.

On the client side, generated code gives you a typed stub with methods corresponding to the service.

Conceptually, application code becomes:

client.GetStock(request)

instead of manually building:

URL
HTTP verb
JSON encoding
response JSON decoding
custom error conventions

That does not mean networking becomes local-function semantics. Latency, timeouts, partial failure, cancellation, and retries still exist.

Generated code improves the contract; it does not remove distributed-systems failure modes.

Protocol Buffers are typed structured messages

Protocol Buffers are a language-neutral, platform-neutral serialization system.

A schema is defined once, and generated bindings represent the same message in languages such as Go, Java, Python, C#, C++, Kotlin, and others.

Compared with free-form JSON, Protobuf gives the compiler/runtime explicit field types and numeric wire identifiers.

That helps with:

  • consistent contracts across languages
  • compact binary messages
  • additive schema evolution
  • generated serialization/deserialization

Do not think of Protobuf as “compressed JSON.” It is a different schema-driven wire format.

gRPC services are remote procedure calls

REST commonly exposes resources:

GET /products/42
POST /orders

gRPC exposes methods:

InventoryService.GetStock
OrderService.CreateOrder

The client calls a method through a stub, and gRPC handles the transport, message framing, metadata, status, and serialization details.

This RPC style often feels natural for internal service APIs where operations are known and both sides share generated contracts.

gRPC has four RPC shapes

Official gRPC documentation defines four service method types.

Unary RPC

One request and one response:

rpc GetStock(GetStockRequest) returns (GetStockResponse);

Conceptually:

request → response

This is the closest equivalent to an ordinary request/response API call.

Server-streaming RPC

One request, then a stream of responses:

rpc WatchJob(WatchJobRequest) returns (stream JobUpdate);

Useful when the server progressively emits several messages for one request.

Client-streaming RPC

The client sends a stream and receives one response:

rpc UploadEvents(stream Event) returns (UploadSummary);

Useful for bounded ingestion-style operations where several messages form one logical RPC.

Bidirectional-streaming RPC

Both sides stream independently:

rpc Sync(stream ClientUpdate) returns (stream ServerUpdate);

Useful for long-lived interactive protocols.

gRPC preserves message order within each individual stream.

Streaming is part of the RPC contract

With gRPC, streaming is declared directly in the service definition rather than being an unrelated transport bolted onto a normal endpoint later.

That gives generated clients/server APIs a clear streaming model.

But a stream still needs application-level rules for:

  • maximum duration
  • maximum in-flight data
  • cancellation
  • recovery after disconnect
  • slow consumers
  • message semantics

A long-lived stream is not a durable queue.

Channels represent client connectivity

A gRPC client creates a channel to a service target.

The channel owns connectivity state and is then used to create generated client stubs.

Conceptually:

channel to inventory.service
        |
        +→ InventoryService client
        +→ Health client

Channels are designed to be reused rather than opening a brand-new transport connection for every RPC.

The exact channel implementation, connection pooling, name resolution, and load balancing behavior varies by language/runtime and service configuration.

HTTP/2 provides important transport properties

Standard gRPC commonly uses HTTP/2.

HTTP/2 gives gRPC capabilities such as:

  • multiplexing multiple RPC streams over connections
  • headers and trailers
  • stream lifecycle control
  • flow-control primitives
  • long-lived bidirectional streams

Do not reduce gRPC to “HTTP/2 + Protobuf,” though. gRPC also defines method naming, framing, status semantics, metadata behavior, code generation conventions, deadlines, health checking, retries, and language APIs.

Metadata is the per-call side channel

gRPC metadata is key-value information associated with an RPC.

Common uses include:

  • authentication credentials
  • trace context
  • correlation IDs
  • request context

For example conceptually:

authorization: Bearer ...
traceparent: ...
x-request-id: req_42

Metadata maps onto HTTP/2 headers/trailers in standard gRPC transport.

Keep core business data in the typed request message. Metadata is best for cross-cutting call context, not hidden required parameters.

Headers and trailers carry different phases of metadata

Initial metadata is sent before the main response payload.

Trailing metadata is sent when the RPC completes and is also used by gRPC's status model.

That gives the protocol a clean way to communicate final call outcome after streamed message data.

This is one reason gRPC error handling does not map exactly to an ordinary JSON body with an HTTP status code.

Every RPC ends with a gRPC status

A gRPC call completes with a status code.

Common codes include:

  • OK
  • CANCELLED
  • INVALID_ARGUMENT
  • DEADLINE_EXCEEDED
  • NOT_FOUND
  • ALREADY_EXISTS
  • PERMISSION_DENIED
  • RESOURCE_EXHAUSTED
  • FAILED_PRECONDITION
  • ABORTED
  • UNIMPLEMENTED
  • INTERNAL
  • UNAVAILABLE
  • UNAUTHENTICATED

These codes help clients distinguish errors that have different handling semantics.

For example:

INVALID_ARGUMENT → fix request, do not blindly retry
UNAUTHENTICATED → obtain valid credentials
PERMISSION_DENIED → caller lacks authorization
UNAVAILABLE → may be transient; retry only when operation is safe
DEADLINE_EXCEEDED → caller's time budget expired

Consistent status-code usage is part of API design.

Deadlines prevent calls from waiting forever

A client can tell gRPC how long it is willing to wait for an RPC.

If the deadline expires, the client receives DEADLINE_EXCEEDED.

Servers can inspect cancellation/deadline state so they can stop work that no caller still wants.

This matters in service chains:

request
  → service A
      → service B
          → service C

Without deadlines, one slow dependency can create requests that keep consuming resources long after the user has timed out.

Cancellation does not roll back completed business work

Either side can cancel an RPC.

Cancellation tells the RPC machinery to stop continuing the call, but gRPC documentation explicitly warns that changes made before cancellation are not automatically rolled back.

If a server charged a card or committed a database transaction before learning that the client cancelled, that business state may still exist.

Design cancellation and idempotency at the application layer.

Retries do not make mutations safe automatically

gRPC supports retry behavior, including configurable policies for selected transient status codes.

But consider:

client sends CreateOrder
server commits order
response is lost
client retries

Without idempotency protection, two orders may be created.

For mutation RPCs, use:

  • idempotency/request keys
  • natural idempotent semantics
  • application-level deduplication

Retry configuration should follow business semantics rather than assuming transport errors imply “nothing happened.”

Authentication and transport security are separate layers

gRPC supports TLS for encrypted transport and server authentication, and many implementations support mutual TLS for client certificates.

Authentication credentials can also be attached through call/channel credential mechanisms and metadata, depending on the platform.

Then the application still performs authorization:

authenticated service/user
        ↓
may this caller invoke this method for this tenant/resource?

mTLS proving service identity does not automatically mean every service is allowed to call every method.

Interceptors provide cross-cutting behavior

Most gRPC language ecosystems support interceptors or similar middleware hooks.

Typical uses include:

  • authentication
  • authorization
  • logging
  • tracing
  • metrics
  • request IDs
  • policy enforcement

Keep business logic in service methods and common transport/call concerns in interceptors where appropriate.

Avoid interceptor stacks so opaque that developers cannot tell why a request was rejected or retried.

gRPC has a standard health-checking API

gRPC defines a standard health service with unary Check and streaming Watch behavior.

That lets clients, load balancers, and monitoring systems use a consistent health contract rather than every team inventing Ping2, Status, or AreYouAlive methods.

Health still needs meaningful state updates from your service.

A process being alive does not necessarily mean it is ready to serve requests.

Reflection improves discoverability

gRPC reflection allows compatible tooling to ask a running server about its services and message schemas.

This can make tools such as interactive RPC clients much easier to use without manually providing descriptor files.

Reflection should be enabled according to your operational/security needs. An internal development environment and an internet-facing production service may choose different exposure policies.

gRPC-Web exists because browsers are different clients

Backend/native gRPC clients can use the normal gRPC protocol stack.

Browsers do not expose the same low-level HTTP/2 capabilities to JavaScript.

The gRPC project therefore provides gRPC-Web, which normally relies on a compatible proxy or server path translating browser-friendly requests to backend gRPC.

This lets browser code use generated gRPC-Web clients, but it is a distinct deployment consideration.

A browser application does not simply point the normal native gRPC library at a backend port.

gRPC is not the same thing as WebSocket

Both can support long-lived communication, but their abstractions differ.

WebSocket

Gives you a bidirectional message transport. You design the application protocol yourself.

gRPC streaming

Gives you typed RPC methods whose request/response streams are defined in the service contract, with gRPC metadata, deadlines, status, and generated APIs.

Choose based on client environment and protocol semantics rather than “both are realtime.”

gRPC is not a message queue

A bidirectional or server stream is live communication between connected endpoints.

If the consumer is disconnected, gRPC does not automatically retain every application message as a durable broker would.

For background work or durable asynchronous delivery, use a queue/event system when that is the actual requirement.

You can combine them:

API service → queue → worker
API service ⇄ another service via gRPC

Different communication patterns solve different coupling problems.

Service definitions need compatibility discipline

Safe evolution usually favors additive changes.

Good practices include:

  • add new fields with new numbers
  • never change an existing field's number
  • reserve deleted field numbers/names
  • avoid changing field meaning while keeping the same number
  • test old clients against new servers
  • test new clients against older supported servers

Generated code catches syntax/type problems. It cannot detect every semantic compatibility break.

Observability should be method-aware

Useful gRPC telemetry includes:

  • service/method name
  • call count
  • status code
  • p50/p95/p99 latency
  • request/response sizes
  • deadlines exceeded
  • cancellations
  • retries
  • active streams
  • stream duration

Trace propagation through metadata lets distributed tracing connect one incoming request to downstream RPCs.

A healthy gRPC platform makes an RPC easy to trace from client call to backend dependency.

A practical request lifecycle

For a unary RPC, a simplified lifecycle is:

client application
  → generated stub
  → gRPC channel
  → transport
  → server gRPC runtime
  → interceptor chain
  → service method
  → response
  → final gRPC status + trailers
  → client stub result

For streaming RPCs, request or response messages repeat inside the same RPC lifecycle until the stream completes, cancels, errors, or reaches its deadline.

What gRPC solves well

gRPC is particularly good at giving backend teams:

  • explicit typed service contracts
  • generated polyglot client/server APIs
  • consistent status semantics
  • integrated unary and streaming methods
  • deadlines and cancellation
  • metadata for auth/tracing
  • standard health checks
  • efficient machine-to-machine serialization by default

Its value is the whole contract/runtime model, not merely one binary format.

What gRPC does not solve for you

You still need to design:

  • service boundaries
  • authorization
  • idempotency
  • retry safety
  • database transactions
  • distributed consistency
  • rate limits
  • backpressure in application queues
  • schema evolution policy
  • deployment compatibility
  • observability

A typed RPC can still be architecturally bad if it is chatty, insecure, unbounded, or tightly couples the wrong services.

Beginner checklist

When learning or introducing gRPC, make sure you understand:

  1. .proto files define services and messages.
  2. Field numbers are durable wire identifiers.
  3. Code generation creates typed clients/server interfaces.
  4. Unary, server-streaming, client-streaming, and bidirectional-streaming RPCs have different lifecycles.
  5. Channels are reusable client connectivity abstractions.
  6. Metadata carries call context such as auth/tracing.
  7. Every call ends with a gRPC status.
  8. Deadlines and cancellation are part of normal RPC design.
  9. Retries require idempotency awareness.
  10. TLS/authentication do not replace authorization.
  11. Browser clients normally use gRPC-Web rather than native gRPC directly.
  12. Streaming is not durable messaging.

The easiest way to understand gRPC is as a typed service-contract system plus an RPC runtime: define methods and messages once, generate code in each language, then let gRPC handle the common transport lifecycle while your application remains responsible for business correctness.

Official references

Tags:gRPCProtocol BuffersHTTP/2APIsRPCBackend Development
ENTERPRISE SAAS ENGINEERING

BUILDING A SAAS PRODUCT?

Explore Lofingo’s end-to-end SaaS platforms, multi-tenant cloud architecture, and high-concurrency backend engineering.

EXPLORE SAAS SERVICES →