Skip to content

Breaking change detection — Usage guide#

This page covers configuration and common usage patterns for buf breaking. For initial setup, see the quickstart. For a list of all rules, see the rules and categories page.

Defaults and configuration#

You configure breaking change detection in the buf.yaml configuration file. If the input doesn't contain a buf.yaml file, the Buf CLI operates as if there's a buf.yaml file with these default values:

buf.yaml
version: v2
breaking:
  use:
    - FILE

You can skip the Buf checker's built-in rules and categories entirely by omitting them and listing categories or rules provided by Buf plugins instead. If any configured Buf plugins have rules where default is true, those rules are automatically checked if the breaking sections of buf.yaml don't list any of the plugin's rules or categories.

Below is an example of each buf breaking configuration option. For more information on specific options and Buf's rules and categories, see the buf.yaml reference and the rules and categories page.

buf.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

Using Buf policies#

Use Buf policies to create sets of breaking change rules that you can share across multiple workspaces.

Using Buf plugins#

To use rules and categories from a Buf plugin, you first need to install the plugin locally (ideally on your $PATH), then configure it in the buf.yaml file. As with Buf's built-in rules and categories, you can specify combinations of rules and categories using use, except, ignore, and ignore_only. For example, if you want to use the CATEGORY_ID_FROM_PLUGIN category from buf-plugin-foo but don't want to check against its RULE_ID_FROM_PLUGIN rule, you'd define it like this:

buf.yaml
version: v2
breaking:
  use:
    - FILE
    - CATEGORY_ID_FROM_PLUGIN # Applies all rules contained in this buf-plugin-foo category
  except:
    - RULE_ID_FROM_PLUGIN # Omits this buf-plugin-foo rule
plugins:
  - plugin: buf-plugin-foo

You can get a list of all of your workspace's rules and categories (including those from configured Buf plugins) by running buf config ls-breaking-rules.

Integration with CI/CD workflows#

Because buf breaking is part of a CLI, you can easily integrate it into CI/CD workflows. For instructions, see the General CI/CD setup and GitHub Action pages.

Usage examples#

The most basic usage of buf breaking is to check your local files against your local Git repository. However, you can specify both the input and the schema you're checking against in multiple ways, so you can use buf breaking in many types of workflows. You must use either the --against or --against-registry flags.

Custom options#

Breaking change detection doesn't work on changes to custom options like google.api.http. Doing breaking change detection for options such as this can't happen easily inside of Buf, because there are an infinite number of these options and the semantics are different for each. So, we don't validate changes to custom options as part of breaking change detection.

Git and GitHub#

Local repositories#

You can directly compare against the .proto files at the head of a git branch or a git tag. See the inputs documentation for details on git branches and git tags. It's especially useful for iterating on your schema locally.

Remote repositories#

Note that many CI services like Travis CI don't do a full clone of your repo, instead cloning a certain number of commits (typically around 50) on the specific branch that you're testing. In this scenario, other branches aren't present in your clone within CI, so the previous local example doesn't work. You can fix this by giving the remote path directly to the Buf CLI so it can clone the repo itself, for example against https://github.com/foo/bar.git:

$ buf breaking --against 'https://github.com/foo/bar.git'

It only clones the single commit at the HEAD of the branch, so even for large repositories, this should be quick.

For remote locations that require authentication, see HTTPS Authentication and SSH Authentication for details.

Using tags#

You can compare against a git tag, for example v1.0.0:

$ buf breaking --against '.git#tag=v1.0.0'

Within subdirectories#

You can compare against a subdirectory in your Git repository. For example, if your buf.yaml file is in the proto subdirectory:

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

Buf Schema Registry#

You can compare a single module against the latest version stored in the BSR:

$ buf breaking --against <REMOTE>/<ORGANIZATION>/<REPOSITORY>
Example
$ buf breaking --against buf.build/acme/petapis

You can also compare all modules in an input (such as your local workspace) at once:

$ buf breaking --against-registry

To use the --against-registry flag, all modules in the input must have a name to be resolvable to the BSR, or buf breaking errors.

Archives (.tar and .zip)#

You can compare against tarballs and zip archives of your .proto files as well. This is especially useful for GitHub, where you can retrieve them for any commit or branch. This example assumes your repo is github.com/foo/bar and COMMIT is a variable storing the commit to compare against:

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

Output as JSON#

You can also output the errors as JSON. The output defaults to a single-line comma-separated message, but you can pipe it to other tools for formatting. For example, you can send the output to jq:

$ 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\"."
}

Limit to specific files#

By default, the Buf CLI builds all files under the buf.yaml configuration file. Instead, you can manually specify the file or directory paths to check. This is an advanced feature intended for editor or Bazel integration. In general, it's better to let the Buf CLI discover all files under management and handle this for you, especially when using the FILE category.

The --path flag limits breaking change detection to the specified files if applied:

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

Advanced use cases#

Due to the nature of inputs, buf breaking happily compares just about anything. You may have an advanced use case, so this example demonstrates its ability to compare a git repository against a remote archive.

Copy/paste this into your terminal:

$ buf breaking \
  "https://github.com/googleapis/googleapis.git" \
  --against "https://github.com/googleapis/googleapis/archive/b89f7fa5e7cc64e9e38a59c97654616ad7b5932d.tar.gz#strip_components=1" \
  --config '{"version":"v2","breaking":{"use":["PACKAGE"]}}'

google/cloud/asset/v1/assets.proto:27:1:File option "cc_enable_arenas" changed from "false" to "true".

To explicitly target a branch, you can adapt the command to include branch=<branch_name> in the git input:

$ buf breaking \
  "https://github.com/googleapis/googleapis.git#branch=main" \
  --against "https://github.com/googleapis/googleapis/archive/b89f7fa5e7cc64e9e38a59c97654616ad7b5932d.tar.gz#strip_components=1" \
  --config '{"version":"v2","breaking":{"use":["PACKAGE"]}}'

google/cloud/asset/v1/assets.proto:27:1:File option "cc_enable_arenas" changed from "false" to "true".