Detecting breaking changes
buf breaking compares the current version of your Protobuf schema against a past version and reports any changes that would break clients, servers, or the code generated from those schemas. The past version can be any input the Buf CLI accepts: a BSR module, a Git repository, a tarball, or a Buf image.
For example, changing a field’s type from int32 to string:
Before
message User {
int32 id = 1;
}After
message User {
string id = 1;
}Running buf breaking against the previous version flags the change:
buf breaking --against '.git#branch=main'
user.proto:2:3:Field "1" on message "User" changed type from "int32" to "string".Tag 1 now carries an incompatible wire type, so every existing client and every serialized message already in flight becomes unreadable. Catching this before merge is the point.
See the quickstart for a hands-on walkthrough.
How compatibility is defined
Protobuf schemas break at different layers. Adding a new field is safe at every layer. Renaming an existing field breaks generated source code but leaves the wire format intact. Changing a field’s type breaks everything.
buf breaking groups its rules into four categories, from strictest to most lenient:
FILE: Detects breakage to generated source code on a per-file basis. Important for languages with file-specific generated imports like C++ or Python. Default whenbreaking.useis omitted frombuf.yaml.PACKAGE: Detects breakage to generated source code on a per-package basis. More lenient thanFILEbecause moving a definition between files in the same package doesn’t break consumers that import the package as a whole.WIRE_JSON: Detects breakage to the binary wire format or JSON encoding.WIRE: Detects breakage to the binary wire format only.
Passing a stricter category implies passing every looser one: schemas that pass FILE also pass PACKAGE, WIRE_JSON, and WIRE. Pick the category that matches what your consumers actually depend on. A schema consumed only over the wire can tolerate WIRE; a schema whose Go generated code is depended on externally needs PACKAGE.
See rules and categories for the full list of rules in each category.
Where breaking change detection runs
Three places, covering the lifecycle from authoring to production:
- Locally. Run
buf breaking --against <past-version>from the command line while you work. - In CI. The same command fits into any pipeline. Buf ships a GitHub Action; the CI/CD integration guide covers other common setups. Failures surface as PR comments next to the lines that introduced them.
- On the BSR. Server-side breaking change checks catch anything CI missed. When a developer pushes a module that would break consumers, the push enters a review flow where repository owners approve or reject the change before it reaches production.
Customizing the rules
The built-in rules and categories cover the common cases. For organization-specific policies, enable or disable individual rules in buf.yaml, or bring your own rules through Buf check plugins. See the usage guide for configuration examples.
Further reading
- Quickstart: Set up breaking change detection in a sample project.
- Usage guide: Configuration options and invocation patterns.
- Rules and categories: Every rule, grouped by category.
- BSR breaking change checks: Enforcing breaking change policy on the registry.