CI/CD for a Protobuf/gRPC Codegen Repo with GitHub Actions
Lint, breaking-check, and publish your shared proto schemas on each push.
A protobuf/gRPC codegen repo is the single source of truth for service schemas consumed by many languages. This recipe lints, checks breaking changes against main, generates stubs, and publishes to a registry.
What the pipeline does
- set up buf
- lint with buf lint
- detect breaking changes with buf breaking against main
- generate multi-language stubs with buf generate
- push the module to the Buf Schema Registry on main
The workflow
buf breaking compares the PR protos against the main branch so backward-incompatible changes fail review. buf push publishes the module so consumers pull versioned stubs.
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
proto:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: bufbuild/buf-action@v1
with:
setup_only: true
- run: buf lint
- run: buf breaking --against '.git#branch=main'
- run: buf generate
- if: github.ref == 'refs/heads/main'
run: buf push
env:
BUF_TOKEN: ${{ secrets.BUF_TOKEN }}Caching and speed
buf is a single fast binary and the dependency graph is small, so runs are quick. The main cost is the breaking-change check fetching main (fetch-depth: 0); cheaper managed runners such as Latchkey keep frequent runs inexpensive and auto-retry transient registry failures.
Publishing
On main, buf push publishes the module to the Buf Schema Registry so downstream services pull versioned, breaking-checked stubs. Consumers run buf generate against the published module instead of vendoring raw .proto files.
Key takeaways
- buf breaking against main blocks backward-incompatible schema changes.
- Publish to a schema registry so consumers pull versioned stubs.
- fetch-depth: 0 is required for the breaking-change comparison.