Migrate from protoc#
The Buf CLI replaces a typical protoc workflow with two commands: buf build for compilation, buf generate for per-language code generation.
Configuration moves out of long shell flags into two YAML files: buf.yaml for include paths, buf.gen.yaml for plugins.
This guide assumes you’re calling protoc directly from scripts or a Makefile.
Install the Buf CLI before continuing.
For other migration paths, see Protolock and Prototool.
A typical protoc setup#
Take a project with a primary module under proto/ and a vendored dependency under vendor/:
.
├── proto
│ └── acme
│ └── weather
│ └── v1
│ └── weather.proto
└── vendor
└── google
└── api
└── annotations.proto
A common protoc invocation to generate Go and gRPC stubs:
$ protoc \
-I proto \
-I vendor \
--go_out=. \
--go_opt=paths=source_relative \
--go-grpc_out=. \
--go-grpc_opt=paths=source_relative \
$(find proto -name '*.proto')
Each -I flag is a directory the compiler searches for imports.
With these -I paths, proto/acme/weather/v1/weather.proto and vendor/google/api/annotations.proto are imported as acme/weather/v1/weather.proto and google/api/annotations.proto.
Convert -I paths to a buf.yaml workspace#
Each protoc -I path becomes a module in buf.yaml.
Place buf.yaml at the directory that’s the common ancestor of every -I path; that directory is the workspace root.
.
├── buf.yaml
├── proto
│ └── acme
│ └── weather
│ └── v1
│ └── weather.proto
└── vendor
└── google
└── api
└── annotations.proto
For common dependencies such as googleapis, prefer a BSR dependency over vendoring when you can:
That keeps third-party schemas out of your repository, avoids counting vendored types as yours on paid BSR plans, and gives every workspace the same dependency version through buf.lock.
Verify the workspace compiles:
buf build reads buf.yaml from the current directory, discovers every .proto file in the configured modules, and compiles them.
With no -o flag, the compiled output is discarded; pass -o lock.binpb to write a binary Buf image.
Convert plugin flags to a buf.gen.yaml#
Each --<lang>_out / --<lang>_opt pair from protoc becomes a plugins entry in buf.gen.yaml.
Place the file alongside buf.yaml:
version: v2
plugins:
- local: protoc-gen-go
out: .
opt:
- paths=source_relative
- local: protoc-gen-go-grpc
out: .
opt:
- paths=source_relative
Run code generation:
buf generate uses the same module discovery as buf build, so there’s no find invocation or explicit input list.
protoc flag reference#
protoc flag |
Buf equivalent | Notes |
|---|---|---|
-I <dir>, --proto_path=<dir> |
A modules[] entry in buf.yaml |
Each -I becomes a path: under modules. |
--<lang>_out=<dir> |
plugins[].out in buf.gen.yaml |
Plus a plugins[].local: or remote: line for the binary or BSR plugin. |
--<lang>_opt=<key>=<val> |
A plugins[].opt entry |
List of key=value strings under the same plugin. |
--descriptor_set_out=FILE |
buf build -o FILE |
Writes a binary Buf image, wire-compatible with FileDescriptorSet. Add --as-file-descriptor-set to drop the extra Buf metadata. |
--include_imports |
(default) | buf build -o includes imports unless you pass --exclude-imports. |
--include_source_info |
(default) | Source code info is included unless you pass --exclude-source-info. |
$(find <dir> -name '*.proto') |
(automatic) | buf build and buf generate discover .proto files from the workspace; no explicit input list is needed. |
Multiple generation templates#
If different parts of the schema need different generation settings (for example, a public API surface vs. a private one), invoke buf generate once per template using --template:
$ buf generate public --template buf.public.gen.yaml
$ buf generate private --template buf.private.gen.yaml
For details, see the buf generate reference.
What buf adds beyond protoc#
The Buf CLI covers steps protoc doesn’t:
buf lint: style and structural checks against a configurable rule set.buf breaking: breaking-change detection against a previous schema (Git ref, BSR module, or stored image).buf format: reformat.protofiles in place.- The BSR: publish modules so they’re consumable by name from other workspaces, with generated SDKs in every supported language.