Code Generation
The compiler and its plugins
Section titled “The compiler and its plugins”A .proto file does nothing on its own. You run it through protoc, the Protocol Buffers compiler, which parses the schema and then hands it to plugins that emit code for a specific language. protoc itself knows nothing about Go or Python — the plugins do.
For gRPC there are usually two outputs:
- Message code — the structs/classes for
User,GetUserRequest, etc. (from the base protobuf plugin). - Service code — the client stub and the server interface (from the gRPC plugin).
flowchart LR proto["user.proto"] --> protoc["protoc (parses schema)"] protoc --> base["protobuf plugin → message types"] protoc --> grpc["gRPC plugin → stub + server interface"]
Running it per language
Section titled “Running it per language”Each language has its own plugin pair. Here is the typical command in each ecosystem:
# install the two plugins oncego install google.golang.org/protobuf/cmd/protoc-gen-go@latestgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ user/v1/user.proto# → user.pb.go (messages) + user_grpc.pb.go (stub + server interface)pip install grpcio-tools
python -m grpc_tools.protoc -I. \ --python_out=. --grpc_python_out=. \ user/v1/user.proto# → user_pb2.py (messages) + user_pb2_grpc.py (stub + servicer)npm install --save-dev ts-proto @grpc/grpc-js grpc-tools
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto \ --ts_proto_out=. --ts_proto_opt=outputServices=grpc-js \ user/v1/user.proto# → user.ts (typed messages + client + server interfaces)What you actually get
Section titled “What you actually get”Whatever the language, the generated code always contains the same three things:
- Message types — a typed object for every
message, with getters/setters or fields and the serialization logic baked in. - A client stub — a class with one method per
rpc, so the client just callsstub.GetUser(req). - A server interface — an abstract base (Go interface, Python servicer, Node service definition) with one method per
rpcfor you to implement.
You never edit generated files. When the .proto changes, you regenerate.
Use buf, not raw protoc
Section titled “Use buf, not raw protoc”Raw protoc commands get unwieldy fast — plugin paths, include paths, output options, multiplied across languages. buf is the modern tool that replaces them. You declare inputs and outputs in a small config file and run one command:
version: v2plugins: - remote: buf.build/protocolbuffers/go out: gen - remote: buf.build/grpc/go out: genbuf generatebuf also lints your schemas and detects breaking changes (covered in the Ecosystem module) — which is why most teams standardize on it.