Build images – Overview

Buf CLI operations are based on Protobuf files that have been successfully compiled, or built. Building an image from the .proto files that define the schema is the first step buf executes when running commands like buf lint and buf breaking. The tooling compiles the .proto files into a single binary file that can be easily shared and stored. Generating an image with buf build, in its simplest form, is a way to verify that the input successfully compiles.

Generally you won't need to generate images directly, but if needed, you can build an image with buf build, where -o tells it to output to the provided file (and its implied format):

$ buf build -o image.binpb

The resulting Buf image is written to the image.binpb file. The ordering of the FileDescriptorProtos is carefully written to mimic the ordering that protoc would produce, for both the cases where imports are and aren't written.

Images can be output in one of three formats:

Any format can be compressed using Gzip or Zstandard. The special value - is used to denote stdout and you can manually set the format. For example:

$ buf build -o -#format=json

Usage examples

Strip imports and source code info

By default, buf produces a Buf image with both imports and source code info. You can strip each of these:

$ buf build --exclude-imports --exclude-source-info -o image.binpb

In general, we don't recommend stripping them, as this information can be useful for various operations. Source code info, however, takes up a lot of additional space (generally ~5x more space), so if you know you don't need this data, it can be useful to leave it out.

Remove ImageFileExtension field

Images always include the ImageFileExtension field. If you want a pure FileDescriptorSet without this field set, to mimic protoc entirely:

$ buf build -o image.binpb --as-file-descriptor-set

The ImageFileExtension field doesn't affect Protobuf plugins or any other operations—they merely see this as an unknown field—but we provide this option in case you need it.

Limit to specific files

By default, buf builds all files under the buf.yaml configuration file. You can instead manually specify the file or directory paths to build. This is an advanced feature intended to be used for editor or Bazel integration—it's better to let buf discover all files under management and handle this for you.

The compiled result is limited to the given files if the --path flag is specified, as in this command:

$ buf build --path path/to/foo.proto --path path/to/bar.proto

Limit to specific types

When you run buf build to create a FileDescriptorSet or Buf image, the output contains all the Protobuf types declared in the module by default. But for some advanced use cases, you may want the image or FileDescriptorSet to contain only a subset of the types described in your Protobuf schemas.

Versions 1.1.0 and later of the buf CLI include a --type option for the buf build command that enables you to supply a fully qualified Protobuf name and limit the resulting image or FileDescriptorSet to only those descriptors required to represent those types and their required dependencies. This example usage restricts the output types to those required to represent pkg.foo.Bar:

$ buf build --type pkg.foo.Bar

The --type flag accepts fully qualified names for messages, enums, and services. These dependent descriptors are included in the build:

  • Messages
    • Messages and enums referenced in message fields
    • Any proto2 extension declarations for message fields
    • The parent message if this message is a nested definition
    • Any custom options for the message, its fields, and the file in which the message is defined
  • Enums
    • The enum value descriptors for this enum
    • The parent message is this enum is a nested definition
    • Any custom options for the enum, enum values, and the file in which the enum is defined
  • Services
    • Request and response types referenced in service methods
    • Any custom options for the services, its methods, and the file in which the service is defined
Supplying multiple types

You can specify multiple types by applying the --type option multiple times, as in this example:

$ buf build \
  --type acme.weather.v1.Units \
  --type acme.weather.v1.CurrentWeather.Temperature

In this case, dependent descriptors for both acme.weather.v1.Units and acme.weather.v1.CurrentWeather.Temperature are included in the output.

As an example, consider these two .proto files:

package pkg;
message Foo {
  optional Bar bar = 1;
  extensions 2 to 3;
message Bar {...}
message Baz {
  other.Qux qux = 1 [(other.my_option).field = "buf"];
package other;
extend Foo {
  optional Qux baz = 2;
message Qux{...}
message Quux{...}
extend google.protobuf.FieldOptions {
  optional Quux my_option = 51234;

This table shows which files, messages, and extensions would be included for various types from foo.proto and bar.proto if specified as the argument to --type:

buf build --type pkg.Foofoo.proto, bar.protopkg.Foo, pkg.Bar, other.Quxother.baz\
buf build --type pkg.Barfoo.protopkg.Bar
buf build --type pkg.Bazfoo.proto, bar.protopkg.Baz, other.Quux, other.Quxother.my_option

Run in Docker

Buf ships a Docker image bufbuild/buf that enables you to use buf as part of your Docker workflow. For example:

$ docker run \
  --volume "$(pwd):/workspace" \
  --workdir /workspace \
  bufbuild/buf build