gRPC and Protocol Buffers

gRPC lets Go services call each other like local functions over the network. You define a contract once in a .proto file, generate typed client and server code with protoc , and get fast binary transport plus streaming over HTTP/2 — a strongly typed alternative to REST/JSON.

Learn gRPC and Protocol Buffers in our free Go course — an interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Go course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ The contract: a .proto file

Everything starts with the schema. A message is a typed struct; each field has a type, a name, and a unique field number (its tag on the wire). A service groups RPC methods. From this one file, protoc generates both the Go structs and the client/server stubs.

2️⃣ The server: grpc.NewServer() and register

Implement the generated GreeterServer interface, then wire it up in three steps: create the server with grpc.NewServer() , register your implementation with pb.RegisterGreeterServer , and call Serve on a listener. Embedding UnimplementedGreeterServer keeps you forward-compatible.

3️⃣ The client: grpc.Dial and call

The client dials the server to get a connection, wraps it in the generated client, and then calls methods as if they were local. Pass a context with a deadline so a hung server can't block you forever.

4️⃣ Streaming: more than one message

Unary is one-in, one-out — but gRPC also streams. Mark a method with the stream keyword in the .proto and the handler gets a stream to Send on (or Recv from) instead of a single return value.

🎯 Your Turn

Finish this unary handler. Fill in the two blanks marked ___ so the server greets the caller by name.

❌ Editing the generated .pb.go files — your changes vanish on regeneration.

✅ Change the .proto and re-run protoc ; never hand-edit generated code.

❌ Renumbering or reusing a field number — breaks already-deployed clients.

✅ Keep field numbers stable forever; add new fields with new numbers.

❌ Forgetting transport credentials on the client — the dial fails.

✅ For local dev pass insecure.NewCredentials() ; use TLS in production.

❌ Not embedding UnimplementedGreeterServer — code breaks when new methods are added.

✅ Embed it so unimplemented methods return a clear error instead of failing to compile.

Server streaming. Mark it in the .proto with returns (stream Reply) ; the handler calls stream.Send repeatedly.

It is the wire tag identifying that field in the binary encoding. It must stay constant across versions for compatibility.

Extend the contract: add AddRequest , AddReply , and an Add RPC on a Calculator service, then regenerate.

Practice quiz

What is a .proto file used for in gRPC?

  • Defining messages and services as the contract between client and server
  • Configuring the network firewall
  • Logging RPC traffic
  • Storing compiled binaries

Answer: Defining messages and services as the contract between client and server. The .proto file is the source of truth: it declares your messages and the service methods both sides agree on.

Which tool generates Go code from a .proto file?

  • grpcurl
  • go build
  • protoc together with protoc-gen-go
  • gofmt

Answer: protoc together with protoc-gen-go. protoc is the Protocol Buffer compiler; the protoc-gen-go and protoc-gen-go-grpc plugins emit the Go types and stubs.

How does Protocol Buffers send data on the wire?

  • As CSV rows
  • As a compact binary format
  • As human-readable JSON
  • As XML

Answer: As a compact binary format. Protobuf serializes to a compact, efficient binary representation, which is smaller and faster to parse than JSON text.

What does the field number after each field in a message mean (e.g. name = 1)?

  • A default value
  • The maximum length
  • An array index that must start at zero
  • A unique tag identifying that field on the wire

Answer: A unique tag identifying that field on the wire. Field numbers are the stable wire identifiers; they must stay constant across versions so old and new code stay compatible.

Which function creates a new gRPC server in Go?

  • grpc.NewServer()
  • grpc.Open()
  • grpc.Listen()
  • grpc.Serve()

Answer: grpc.NewServer(). grpc.NewServer() returns a *grpc.Server; you then register your service and call Serve on a net.Listener.

How does a client establish a connection to a gRPC server?

  • grpc.Accept()
  • grpc.Dial (or grpc.NewClient) to get a *grpc.ClientConn
  • http.Get on the service URL
  • net.Listen on the port

Answer: grpc.Dial (or grpc.NewClient) to get a *grpc.ClientConn. The client dials the target address to obtain a *grpc.ClientConn, which it passes to the generated client constructor.

What is a UNARY RPC?

  • A call that never returns
  • A call with no request message
  • A stream of requests
  • A single request that returns a single response

Answer: A single request that returns a single response. Unary is the simplest pattern: one request in, one response out, like a normal function call over the network.

Which streaming pattern lets BOTH sides send a stream of messages at once?

  • Client streaming
  • Unary
  • Bidirectional streaming
  • Server streaming

Answer: Bidirectional streaming. Bidirectional streaming opens two independent streams so client and server can read and write concurrently.

After registering your implementation, which call starts handling requests?

  • server.Run()
  • server.Serve(listener)
  • server.Start()
  • server.Handle()

Answer: server.Serve(listener). grpcServer.Serve(lis) blocks and serves incoming connections on the provided net.Listener until it stops.

A key advantage of gRPC over plain REST/JSON is that it...

  • generates strongly typed client and server code from one contract
  • requires no schema at all
  • only works in the browser
  • cannot do streaming

Answer: generates strongly typed client and server code from one contract. From a single .proto contract gRPC generates typed stubs for both sides, plus efficient binary transport and built-in streaming over HTTP/2.