The usual way to work with Protobuf is to generate code. You run a compiler over your .proto files, and plugins emit the types, binary serializers, JSON mapping, and RPC stubs for your language.
edition = "2024"; package intro.v1; message User { int64 id = 1; string name = 2; uint32 age = 3; float height_cm = 4; double weight_kg = 5; bool verified = 6; }
What you get
Once code is generated from this schema, you can create User objects in your language with type checking and editor support, and convert them to compact binary or JSON for sending or storing.
Generating Code with buf
This guide uses the Buf CLI, which keeps generation declarative with a buf.gen.yaml file. Checking it into your repo lets everyone on the team generate the same output with one command. The remote plugins in this example run on the Buf Schema Registry, so there are no plugin binaries to install locally, and pinning their versions keeps everyone's output identical. The buf.yaml beside it marks proto/ as the root of the schema files. Go code also needs an import path for each file; managed mode fills in go_package from the prefix, so you don't have to set it in the schema.
version: v2 modules: - path: proto
version: v2 managed: enabled: true override: - file_option: go_package_prefix value: example.com/gen/go plugins: - remote: buf.build/bufbuild/es:v2.14.0 out: web/src/gen opt: target=ts - remote: buf.build/protocolbuffers/go:v1.36.12 out: gen/go opt: paths=source_relative
$ buf generateGenerating with protoc
protoc is the reference compiler for Protobuf. Plugins (like protoc-gen-es) are executables that protoc finds on your PATH, or at the path you give it with --plugin. Without managed mode, the Go import path comes from a go_package option in the file or an M flag on the command line. protoc creates the folders inside each output directory but not the output directory itself, so make those first.
$ npm install @bufbuild/protobuf $ npm install --save-dev @bufbuild/protoc-gen-es $ go get google.golang.org/protobuf@v1.36.12 $ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.12
$ mkdir -p web/src/gen gen/go $ protoc -I proto \ --plugin=protoc-gen-es=node_modules/.bin/protoc-gen-es \ --es_out=web/src/gen --es_opt=target=ts \ --go_out=gen/go --go_opt=paths=source_relative \ --go_opt=Mintro/v1/user.proto=example.com/gen/go/intro/v1 \ proto/intro/v1/user.proto
Using the Generated Code
With code generated by protobuf-es, the schema becomes a native TypeScript API.
import { create, toBinary, toJsonString } from "@bufbuild/protobuf"; import { UserSchema } from "./gen/intro/v1/user_pb"; const user = create(UserSchema, { id: 1042n, name: "cyber_ninja", age: 28, verified: true, }); const bytes = toBinary(UserSchema, user); const json = toJsonString(UserSchema, user); console.log("JSON Output:", json); console.log("Binary Output:", bytes);
Further Reading
- The modern Protobuf workflow
How linting, code generation, and breaking-change checks fit together in a schema-first workflow.
- Protobuf-ES: the TypeScript runtime we all deserve
The design behind the generated TypeScript that powers the site's demos.
- Getting started in Go
The official Go tutorial: generate code from a .proto and use it to write and read messages.
- Getting started in Python
Generating Python code from a schema and using the Protobuf runtime API.
- Getting started in TypeScript
The Protobuf-ES guide: the same runtime the site's interactive demos use.
- Getting started in Java
The official Java tutorial.
- Getting started in Kotlin
The official Kotlin tutorial.
- Getting started in C++
The official C++ tutorial.
- Getting started in C#
The official C# tutorial.
- Getting started in Dart
The official Dart tutorial.
Next
Services
Defining RPC interfaces with the Protobuf service keyword: unary and streaming methods, and how frameworks like gRPC and ConnectRPC generate clients and servers.