Skip to content
S
distributed systems

Introduction to gRPC

Updated · originally #grpc#distributed-systems7 min read

Intro

gRPC is a contract-first RPC framework commonly used for service-to-service communication. You define operations and messages in a schema, generate strongly typed client and server APIs, and send calls over HTTP/2. Protocol Buffers are the default message format.

This article explains how those pieces fit together, the four RPC styles, and when gRPC is a better fit than an HTTP/JSON API or WebSocket connection.

Motivation

Many getting-started guides jump straight to generated files and framework commands. That makes the example run, but it can hide the important boundaries: which parts come from the .proto contract, which parts are generated, what HTTP/2 contributes, and what the application still needs to handle.

This series starts with that mental model and then applies it in Go and .NET.

Background

gRPC is one option in a much larger API toolbox. It does not replace every style below. Each one optimizes for a different interaction model.

  • SOAP - A message-oriented protocol with formal service contracts and an extensive standards ecosystem. XML and the surrounding specifications can be heavy, but SOAP remains useful in systems that depend on those standards.
  • REST - A resource-oriented architectural style commonly implemented with HTTP and JSON. It works especially well for public APIs, browsers, caching, and systems that benefit from standard HTTP semantics.
  • GraphQL - A query language and execution model that lets clients request specific fields from a typed schema. It is usually served over HTTP, but it is not tied to HTTP/1.x.

Long-lived and event-driven communication introduces another set of choices:

  • WebSockets - A full-duplex connection where the application defines its own message semantics. It is useful for interactive browser applications and other sessions where either side must send at any time. My WebSocket protocol walkthrough explains the upgrade and framing model.
  • Server-Sent Events - A browser-friendly, server-to-client event stream over HTTP. It is a good fit when updates only need to travel in one direction.

The choice is not simply binary versus text. The useful questions are whether the API is resource-oriented or operation-oriented, who owns the contract, whether streaming is required, which clients must connect, and how the system will evolve that contract safely.

Hello gRPC

Google released gRPC as an open-source project in 2015. It provides remote procedure call semantics over HTTP/2, with libraries for multiple languages. A client calls a generated method, while the gRPC runtime handles message serialization, HTTP/2 streams, metadata, status codes, cancellation, and other transport details.

That local-method shape is convenient, but the call is still remote. It can time out, arrive after a deadline, be cancelled, fail partway through a stream, or complete on the server after the client has stopped waiting. Production clients still need explicit deadlines, deliberate retry policies, authentication, and observability.

💡 Even before we start learning about gRPC, you might wonder what the “g” means. The project has used a different backronym for each release. You can find the list here, which is, by the way, hilarious! 😂

introduction-to-grpc
Source: https://grpc.io/docs/what-is-grpc/introduction/

RPC has been around for decades. gRPC packages the model around an explicit service definition, generated APIs, and a consistent wire protocol. That makes it a strong option for inter-process communication between services written in different languages, especially when both sides are controlled by the same organization.

Protocol Buffers

Protocol Buffers provide both a language-neutral schema and a binary serialization format. gRPC uses .proto files as its default Interface Definition Language, although gRPC implementations can support other message formats.

The usual workflow is:

  1. Define typed request and response messages.
  2. Define service methods and their input and output messages.
  3. Generate message types plus client and server APIs for each implementation language.

It is worth separating the contract from the generated code. The .proto file is the shared source of truth. Generated files are language-specific build artifacts derived from it.

Suppose we want to model a bookshop that returns its available books:

Protocol Buffers
syntax = "proto3";

message Book {
  string title = 1;
  string author = 2;
  int32 page_count = 3;
  optional string language = 4;
}

message GetBookListRequest {}
message GetBookListResponse { repeated Book books = 1; }

service Inventory {
  rpc GetBookList(GetBookListRequest) returns (GetBookListResponse) {}
}

We will use this contract throughout the series.

introduction-to-grpc-2

  • syntax = "proto3" selects the proto3 language syntax explicitly.
  • Book is a message with typed fields. The numeric field identifiers are part of the wire contract, so they must not be changed or reused after publication.
  • repeated Book books = 1 represents a collection of books in the response.
  • Inventory defines the remotely callable service, while GetBookList is a unary RPC with one request and one response.

The contract can be shared across teams and used to generate compatible clients and servers in different languages. Protocol Buffers also preserve unknown fields in their binary form, which helps old and new versions interoperate when schemas evolve compatibly.

Protocol Buffer payloads are compact because field numbers and wire types are encoded instead of repeating field names. They are often smaller and faster to parse than equivalent JSON, but the actual difference depends on the data, implementation, compression, and workload. Measure it when the performance claim matters.

gRPC Server & Client

Once we have the contract, the Protocol Buffer compiler and a language-specific gRPC plugin generate the message types and service APIs. Modern Go and .NET projects usually integrate this generation into their normal build tooling.

introduction-to-grpc

  1. Define the service and its messages in a .proto file.
  2. Generate a server API in the implementation language. The application implements the generated service base or interface.
  3. Generate a client API in any supported language. The client and server languages do not need to match.
  4. Create a channel to the server and invoke unary or streaming methods over HTTP/2.

Generated code removes repetitive serialization and dispatch code. It does not remove the need to design version-compatible messages or handle distributed-system failure modes.

gRPC Modes

gRPC defines four service method shapes. The official core concepts guide documents their lifecycle in detail.

  1. Unary RPC - The client sends one request and receives one response.
  2. Server streaming RPC - The client sends one request and reads an ordered stream of response messages.
  3. Client streaming RPC - The client sends an ordered stream of request messages and receives one response.
  4. Bidirectional streaming RPC - The client and server each send an independent ordered stream of messages. Neither side has to wait for the other stream to finish before writing.

Streaming still needs backpressure, cancellation, deadlines, message-size limits, and bounded resource usage. gRPC uses HTTP/2 framing rather than HTTP/1.1 chunked transfer encoding. If you want to compare the two models, the chunked transfer encoding walkthrough shows how an unknown-length response is framed under HTTP/1.1.

Pros and Cons

Whether gRPC is a good fit depends on who owns the clients, the interaction model, and the operational constraints.

Pros

  • A precise, language-neutral contract with generated, strongly typed APIs.
  • Unary, server-streaming, client-streaming, and bidirectional-streaming methods under one model.
  • HTTP/2 multiplexing, flow control, metadata, deadlines, cancellation, and standard gRPC status codes.
  • A good fit for polyglot service-to-service communication where both sides can adopt gRPC tooling.

Cons

  • Browsers do not expose the full native gRPC transport directly. Browser clients generally use gRPC-Web with a compatible server or proxy, and some streaming modes differ.
  • Binary payloads and HTTP/2 framing are less convenient to inspect with ordinary browser and command-line HTTP tools.
  • Schema evolution requires discipline. Field numbers cannot be casually changed or reused, and generated clients must be distributed to consumers.
  • gRPC does not automatically make calls reliable. Teams still need deadlines, safe retry rules, authentication, load balancing, and observability.
  • A conventional HTTP/JSON API may be simpler for public APIs, cache-oriented resources, and clients that cannot adopt generated libraries.

Conclusion

gRPC works best when a shared contract and generated APIs reduce friction between services, while the team remains explicit about the fact that every call crosses a network. The next articles put the model into practice by building the server in Go and the server in .NET. Thanks for reading ✌️

References

  1. Introduction to gRPC
  2. gRPC core concepts, architecture, and lifecycle
  3. Protocol Buffers proto3 language guide
  4. Protocol Buffers encoding
  5. gRPC-Web basics

Stay in the loop

Practical engineering notes, without the inbox noise.

Notes on distributed systems, resilient software, and engineering in the real world - usually once or twice a month.

Unsubscribe anytime. See what you get, or prefer a feed? Subscribe via RSS.