Basic setup

Add .github/workflows/buf-ci.yaml to the repo:

name: Buf CI
on:
  push:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]
  delete:
permissions:
  contents: read
  pull-requests: write
jobs:
  buf:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: bufbuild/buf-action@v1
        with:
          token: ${{ secrets.BUF_TOKEN }}

This default config:

  • Runs build, lint, format, and breaking change checks on every PR
  • Pushes named modules to the BSR on git push/tag/branch
  • Archives BSR labels when a branch or tag is deleted

BSR (Buf Schema Registry) — Buf’s hosted registry for sharing and versioning protobuf schemas, similar to npm for protos.

Skip breaking change detection

Via PR label

Add the label buf skip breaking to the PR. Requires labeled/unlabeled in the trigger (already in the default config above).

Via commit message

- uses: bufbuild/buf-action@v1
  with:
    breaking: |
      contains(fromJSON('["push", "pull_request"]'), github.event_name) &&
      !contains(github.event.head_commit.message, 'buf skip breaking')

Disable label-skip entirely

breaking: ${{ github.event_name == 'pull_request' }}

Disable individual steps

Each step has a boolean parameter:

- uses: bufbuild/buf-action@v1
  with:
    format: false   # disable formatting
    lint: false     # disable linting

Trigger steps on specific events

- uses: bufbuild/buf-action@v1
  with:
    format: ${{ contains(fromJSON('["push", "pull_request"]'), github.event_name) }}

Common values for github.event_name:

  • push — commit pushed to a branch or tag
  • pull_request — PR opened, updated, or labeled
  • delete — branch or tag deleted
  • release — GitHub release created/published
  • workflow_dispatch — manually triggered from the Actions UI
  • schedule — cron-based trigger

Only push when proto files change

By default the workflow runs on every push regardless of what changed. Use paths to skip runs when no proto-related files were modified:

on:
  push:
    paths:
      - '**.proto'
      - '**/buf.yaml'
      - '**/buf.lock'
      - '**/buf.md'
      - '**/README.md'
      - '**/LICENSE'

Non-root module

By default buf-action looks for buf.yaml at the repo root. If your protos live in a subdirectory (e.g. proto/), point input at it. You also need to tell the breaking change detector where to find the base version of that subdirectory.

Option 1 — clone the base on the fly (simpler, one checkout):

- uses: bufbuild/buf-action@v1
  with:
    input: proto/
    breaking_against: ${{ github.event.repository.clone_url }}#format=git,commit=${{ github.event.pull_request.base.sha }},subdir=proto/

breaking_against clones the repo at the PR’s base commit and points into the same subdirectory, so the detector compares proto/ on your branch against proto/ on the base branch.

Option 2 — check out both explicitly (more control, works in restricted network environments):

- uses: actions/checkout@v4
  with:
    path: head          # current branch lands here
- uses: actions/checkout@v4
  with:
    path: base
    ref: ${{ github.event.pull_request.base.sha }}   # base branch lands here
- uses: bufbuild/buf-action@v1
  with:
    input: head/proto/
    breaking_against: base/proto/

Setup only (run buf manually after)

- uses: bufbuild/buf-action@v1
  with:
    setup_only: true
- run: buf build --error-format github-actions

Pin buf version

- uses: bufbuild/buf-action@v1
  with:
    version: "1.68.4"

If version is unset, the action resolves which buf binary to use in this order:

  1. $BUF_VERSION env var — lets you override per-job without changing the workflow file
  2. buf already installed on the runner — reuses whatever version the GitHub-hosted runner ships with
  3. Latest GitHub release — fetched at runtime, so builds are not reproducible without pinning

Disable PR summary comment

Remove pull-requests: write permission and set:

- uses: bufbuild/buf-action@v1
  with:
    pr_comment: false

See also

  • codegen-multi-service — generating Go code from protos across services, which this action validates and pushes
  • field-numbers — protobuf field number rules; breaking change detection catches violations of these