Skip to content

Configure and run buf breaking

buf breaking compares a Protobuf schema against an earlier version and reports any rules that the newer version breaks. Every run takes two inputs: the current schema (your workspace, by default) and a baseline passed as --against or --against-registry.

sh
buf breaking --against '.git#branch=main'

A baseline can be a Git reference, a module on the Buf Schema Registry, a tarball, or a zip archive. This page covers how to configure rules and how to point buf breaking at each kind of baseline. For a first walk-through, see the quickstart. For every available rule, see the rules and categories page.

Configure in buf.yaml

Breaking change rules live in the buf.yaml file at the root of your workspace. With no configuration, buf breaking behaves as if this were written:

buf.yaml

yaml
version: v2
breaking:
  use:
    - FILE

A complete configuration uses use, except, ignore, ignore_only, ignore_unstable_packages, and a list of plugins:

buf.yaml

yaml
version: v2
breaking:
  use:
    - FILE
  except:
    - RPC_NO_DELETE
  ignore:
    - foo/bar.proto
  ignore_only:
    FIELD_SAME_JSON_NAME:
      - baz
  ignore_unstable_packages: true
plugins:
  - plugin: buf-plugin-foo

See the buf.yaml reference for the full shape of the breaking block, and rules and categories for the rules that ship with the Buf CLI.

Choose a baseline to compare against

buf breaking needs a baseline to diff against. Pass it as --against <input>, where <input> is a Buf input: a Git reference, a BSR module, or an archive. To compare every named module in your workspace against its latest published version on the BSR, use --against-registry instead.

Local Git repository

Compare your working tree against a branch, tag, or commit in the local Git repository:

sh
buf breaking --against '.git#branch=main'
buf breaking --against '.git#tag=v1.0.0'

This is the common shape when iterating on a schema locally. See the Git input reference for every available option.

Remote Git repository

Many CI services, including GitHub Actions, run shallow clones that don’t include the branches you want to diff against. Point buf breaking at the remote URL and the Buf CLI clones only the single commit it needs, so this stays fast even on large repositories:

sh
buf breaking --against 'https://github.com/acme/petapis.git'

For repositories that require authentication, see HTTPS authentication and SSH authentication.

Subdirectory within a repository

If your buf.yaml lives in a subdirectory, include subdir= in the input:

sh
buf breaking --against '.git#tag=v1.0.0,subdir=proto'

Module on the Buf Schema Registry

Compare a single module against its latest published version:

sh
buf breaking --against buf.build/acme/petapis

To compare every module in your workspace at once, use --against-registry:

sh
buf breaking --against-registry

--against-registry is the preferred form when every module in the workspace has a name, and errors if any module is missing one.

Archive (.tar.gz or .zip)

buf breaking accepts tarballs and zip archives. This is convenient for GitHub, which serves an archive for any commit or branch:

sh
buf breaking --against "https://github.com/acme/petapis/archive/${COMMIT}.tar.gz#strip_components=1"
buf breaking --against "https://github.com/acme/petapis/archive/${COMMIT}.zip#strip_components=1"

Narrow the check to specific files

By default, buf breaking checks every file in the workspace. Use --path to restrict the check to specific files:

sh
buf breaking --against '.git#branch=main' --path path/to/foo.proto --path path/to/bar.proto

This is an advanced option, intended for editor or Bazel integrations. In most cases, letting buf breaking discover files itself produces better results, especially when using the FILE category.

Format output as JSON

Output defaults to one violation per line. Pass --error-format=json to emit each violation as a JSON object, suitable for piping into jq or other tools:

sh
buf breaking --against '.git#branch=main' --error-format=json | jq .

{
  "path":"acme/pet/v1/pet.proto",
  "start_line":18,
  "start_column":3,
  "end_line":18,
  "end_column":9,
  "type":"FIELD_SAME_TYPE",
  "message":"Field \"1\" on message \"Pet\" changed type from \"enum\" to \"string\"."
}

Plugins and policies

Rules can come from Buf plugins in addition to the built-ins. To use a plugin, install it (ideally on your $PATH) and list it under plugins in buf.yaml. Its rules and categories then mix with the built-ins under use, except, ignore, and ignore_only:

buf.yaml

yaml
version: v2
breaking:
  use:
    - FILE
    - CATEGORY_ID_FROM_PLUGIN
  except:
    - RULE_ID_FROM_PLUGIN
plugins:
  - plugin: buf-plugin-foo

If a plugin rule has default: true and the breaking block doesn’t list any of the plugin’s rules or categories, that rule runs automatically.

Run buf config ls-breaking-rules to list every rule active in the current workspace, including rules contributed by plugins.

To share a set of breaking-change rules across multiple workspaces, use Buf policies.

Run in CI

buf breaking is built for CI pipelines. For setup, see CI/CD setup and the GitHub Actions guide.