Microservices & gRPC

Microservices: Switching to gRPC (and Connect)

REST is fine for public APIs. But for internal communication between microservices, JSON over HTTP/1.1 is inefficient (text parsing, no types, high overhead).

gRPC (Google Remote Procedure Call) is the standard for high-performance internal traffic.

The Protocol Buffers (Protobuf)

You define your data and service in a .proto file.

syntax = "proto3";

service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
}

message UserRequest {
  string id = 1;
}

message UserResponse {
  string name = 1;
  int32 age = 2;
}

Then, you compile this using protoc to generate Go code. * Strict Types: The generated code guarantees the wire format matches the struct. * Binary: Messages are binary (smaller, faster to parse than JSON).

The gRPC Complexity (and the Solution: ConnectRPC)

Classic gRPC requires special load balancers (because it breaks HTTP/1.1 framing) and is hard to debug with curl.

In 2026, we prefer ConnectRPC (by Buf). * It’s just HTTP: It supports gRPC but also standard HTTP/JSON. * You can curl a Connect service with JSON, but talk to it via gRPC from other Go services.

Connect Example

package main

import (
    "context"
    "net/http"
    "connectrpc.com/connect"
    user "example/gen/user/v1" // Generated code
    "example/gen/user/v1/userv1connect"
)

type UserServer struct {}

func (s *UserServer) GetUser(
    ctx context.Context,
    req *connect.Request[user.UserRequest],
) (*connect.Response[user.UserResponse], error) {
    return connect.NewResponse(&user.UserResponse{
        Name: "Alice",
        Age:  30,
    }), nil
}

func main() {
    mux := http.NewServeMux()
    path, handler := userv1connect.NewUserServiceHandler(&UserServer{})
    mux.Handle(path, handler)
    http.ListenAndServe(":8080", mux)
}

When to use Microservices?

Default to Monolith. Microservices introduce: 1. Network Latency. 2. Distributed Tracing requirements. 3. Deployment complexity.

Only switch to Microservices (and gRPC) when: * You have distinct teams who need to deploy independently. * You have distinct scaling requirements (e.g., the Video Encoder needs 100 GPUs, but the Login server needs 1 CPU).