Skip to content

CI/CD setup (non-GitHub-Actions)

Buf ships a dedicated GitHub Action that covers the common cases. This page covers every other CI system: CircleCI, Travis, Jenkins, GitLab, Buildkite, and anywhere else you run your own worker.

Running Buf in CI usually means three things: installing the Buf CLI on a worker, running buf lint and buf breaking against your schemas, and optionally authenticating to the BSR to push or pull modules.

Install the Buf CLI on a worker

Download the release binary as part of your job setup. The script below installs it to ~/bin/buf and adds that directory to PATH for subsequent steps.

install.sh

sh
#!/bin/bash
set -euo pipefail

BUF_VERSION=1.68.2
BIN_DIR="$HOME/bin"

mkdir -p "$BIN_DIR"
curl -sSL \
    "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-$(uname -s)-$(uname -m)" \
    -o "$BIN_DIR/buf"
chmod +x "$BIN_DIR/buf"

# Expose the binary to later steps in the same job.
export PATH="$BIN_DIR:$PATH"

If you’d rather build from source, see Install the Buf CLI.

Run lint and breaking-change checks

With buf.yaml at the repository root:

sh
buf lint
buf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main"

If your buf.yaml lives in a subdirectory (say, proto/), pass that as the input and add subdir= to the --against reference:

sh
buf lint proto
buf breaking proto --against "https://github.com/<your-org>/<your-repo>.git#branch=main,subdir=proto"

Both https:// and ssh:// remotes work; https:// is the better default for public CI because it avoids the SSH-key setup step. Many CI systems (Travis, CircleCI) only clone the branch under test, so passing the remote explicitly is what lets buf breaking resolve main.

Handle concurrent merges

If two feature branches are opened from the same main and land sequentially, buf breaking can report a false positive on the second branch: the second branch is compared against the main that already contains the first merge, and unrelated additions can look like deletions.

Merge main into the feature branch before the check to avoid this:

sh
git fetch origin
git merge origin/main
buf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main"

If you don’t want the merge commit in the branch, stage it and abort after the check runs:

sh
git fetch origin
git merge --no-commit --no-ff origin/main
buf breaking --against "https://github.com/<your-org>/<your-repo>.git#branch=main"
git merge --abort

See Detect breaking changes for more on what buf breaking considers a breaking change.

Authenticate to the BSR

Pushing modules, creating labels, or pulling from a private repository requires a BSR token. Store it as an encrypted secret in your CI system and expose it to the job as BUF_TOKEN:

With BUF_TOKEN set, the Buf CLI authenticates every BSR request automatically; no additional step is needed. If you need to write credentials to .netrc instead (for tools invoked alongside Buf), pipe the token into buf registry login:

sh
echo "$BUF_TOKEN" | buf registry login --username "$BUF_USER" --token-stdin

For the full auth model, see Authentication.

Cache module downloads

The Buf CLI downloads BSR dependencies into a local module cache. Caching that directory between CI runs avoids re-downloading the same modules on every job.

By default the cache lives under ~/.cache. Set BUF_CACHE_DIR to move it somewhere your CI system caches by default:

sh
export BUF_CACHE_DIR="$CI_WORKSPACE/.buf-cache"

See the module cache reference for what gets stored and how to invalidate it.