Skip to content

Migrate from Prototool#

Prototool was Uber’s Protobuf tool covering compilation, linting, breaking-change detection, formatting, gRPC calls, and plugin execution. Uber archived the project in 2020.

This guide is a lookup reference for repositories that still carry a prototool.yaml or shell scripts wrapping prototool. Each section maps a Prototool surface to its current Buf CLI equivalent.

For installation, see the Buf CLI installation guide; for a hands-on intro, see the CLI quickstart.

Configuration mapping#

prototool.yaml field buf.yaml (v2) field Notes
excludes modules[].excludes Per-module exclude paths.
lint.group lint.use Buf takes a list of categories or rule IDs, not a single named group.
lint.ignores lint.ignore_only Per-rule path ignores. Use lint.ignore to skip a path for every rule.
lint.rules lint.use and lint.except Buf splits add/remove between two keys.
break.include_beta breaking.ignore_unstable_packages Approximate inverse: Buf ignores all unstable suffix forms (alpha, beta, v1alpha1, and so on), not only beta.
generate buf.gen.yaml Code generation moved to its own config file.

For the full set of lint keys (including enum_zero_value_suffix, service_suffix, and the rpc_allow_* options), see the usage guide.

Command mapping#

Prototool Buf CLI Notes
prototool compile buf build
prototool format buf format
prototool generate buf generate Configure plugins in buf.gen.yaml.
prototool lint buf lint --json becomes --error-format=json.
prototool lint --list-linters buf config ls-lint-rules
prototool lint --list-all-linters buf config ls-lint-rules --all Lists every rule across configurations, not just the ones currently configured.
prototool break check --git-branch main buf breaking --against '.git#branch=main' For tags: '.git#tag=v1.0.0'. See the inputs reference for the full Git input grammar.
prototool break check --descriptor-set-path lock.binpb buf breaking --against lock.binpb
prototool config init buf config init
prototool descriptor-set buf build --exclude-imports --exclude-source-info -o - Writes a binary Buf image to stdout. Add --as-file-descriptor-set to drop the extra Buf metadata; replace -o - with a file path to write to disk.
prototool files buf ls-files
prototool grpc buf curl
prototool version buf --version

No direct equivalent#

These Prototool surfaces don’t have a Buf counterpart:

  • prototool all. Run the individual Buf commands you need (buf build, buf lint, buf format, buf breaking).
  • prototool create. Buf doesn’t generate .proto templates.
  • prototool cache. Buf doesn’t shell out to protoc and has no compiler cache; see the internal compiler.
  • prototool x inspect. For schema inspection, run buf build -o -#format=json | jq to read a compiled image as JSON.
  • prototool.yaml keys protoc, create, lint.file_header, lint.java_package_prefix, and break.allow_beta_deps. Buf doesn’t download or invoke protoc, doesn’t lint specific file option values (see What we left out), and doesn’t enforce package dependency restrictions.

Lint rule mapping#

google#

There’s no exact Buf equivalent for the google lint group. The closest baseline is BASIC with the lower_snake_case rules removed; for finer control, compose a lint.use list from the rules catalog.

buf.yaml
version: v2
lint:
  use:
    - BASIC
  except:
    - ONEOF_LOWER_SNAKE_CASE
    - PACKAGE_LOWER_SNAKE_CASE

uber1, uber2#

Both lint groups are supersets of Buf’s STANDARD category, with different suffix conventions. This Buf config is the closest equivalent:

buf.yaml
version: v2
lint:
  use:
    - STANDARD
  enum_zero_value_suffix: _INVALID
  service_suffix: API

The one place this breaks down is uber1’s nested enum prefix. uber1 expects the enclosing message name to appear in nested enum value names:

// uber1: valid
// Buf's ENUM_VALUE_PREFIX rule rejects this
message Foo {
  enum Bar {
    FOO_BAR_INVALID = 0;
    FOO_BAR_ONE = 1;
  }
}

Buf and uber2 both expect the prefix to use only the enum’s own name:

message Foo {
  enum Bar {
    BAR_INVALID = 0;
    BAR_ONE = 1;
  }
}

Protobuf’s C++ scoping rules allow nested enums in different messages to share value names, so the shorter prefix is sufficient.

Breaking change detection#

buf breaking is fully configurable. Pick which categories to apply, and override individual rules per directory or file. See breaking rules for the four built-in categories: FILE, PACKAGE, WIRE, and WIRE_JSON.

If you want to keep your existing protoc invocation and run Buf’s lint or breaking-change checks against the FileDescriptorSet it produces, use protoc-gen-buf-lint and protoc-gen-buf-breaking.

Docker#

The Buf CLI is published at bufbuild/buf. The image’s ENTRYPOINT is buf, so omit buf from the docker run invocation:

$ docker pull bufbuild/buf:1.70.0
$ docker run --rm --volume "$(pwd):/workspace" --workdir "/workspace" \
    bufbuild/buf:1.70.0 lint

Pin to a specific tag in CI so behavior stays reproducible across runs.