Buf CLI

Managed mode

Managed mode is Buf's solution for decoupling API producer concerns from consumer concerns. Protobuf code generation includes a set of options related to language and package output, optimization strategies, and other details that give API consumers fine-grained controls over their generated code. However, Protobuf requires these options to be defined by the API producers and specified in the schema, taking away some of the freedom that the options attempt to offer (since different consumers of the same API might want to generate code differently).

When managed mode is enabled, both producers and consumers can work with these options optimally:

  • Producers can leave them out of the API definition entirely, freeing them from determining a “correct” implementation when there may be many acceptable ways of generating code from their schemas.
  • Consumers actually have the control over generated code output that the options imply, and because managed mode has a thoughtful set of default values, may not need to specify the options further. They can simply enable it with two lines of code and get the output they need.

For example in this weather.proto file, four file options are set:

acme/weather/v1/weather.proto
syntax = "proto3";

package acme.weather.v1;

option go_package = "github.com/acme/weather/gen/proto/go/acme/weather/v1";
option java_multiple_files = true;
option java_outer_classname = "WeatherProto";
option java_package = "com.acme.weather.v1";

// Messages, enums, etc.

None of them have anything to do with the actual API definition in Protobuf, and different consumers may want to use different values for these options. A Java developer, for example, may want to specify a java_package that matches their organization.

The problem really comes to a head when it comes to import paths. With protoc, a Go developer would either need to:

  • specify a value for go_package in their .protofile, or
  • use Mfile=go_package via --go_opt on a per-file basis to set or override the go_package value in a .proto file (this would be the flag for the .proto file above):
 --go_opt=Macme/weather/v1/weather.proto=github.com/acme/weather/gen/proto/go/acme/weather/v1

When managed mode is enabled in your buf.gen.yaml configuration file, the Buf CLI sets your specified file options on the fly during code generation so that you don't need to hard-code them in your .proto files. If its defaults match your desired output, you won't need to set the individual options at all.

Managed mode provides options for choosing an optimization strategy, and for these languages:

  • C++
  • C#
  • Go
  • Java
  • Objective-C
  • PHP
  • Ruby

If you're generating code for a language that isn't on this list, managed mode has no implications and enabling it has no effect. And if you're generating Swift code, Protobuf does offer a swift_prefix option, but Apple specifically counsels against using it, so managed mode doesn't support it.

Configuration

To enable managed mode, set the managed.enabled option in your buf.gen.yaml configuration file. This will cause the file options to match the default behavior described below.

buf.gen.yaml
version: v1
managed:
  enabled: true
  // Managed mode options

// Plugins and other configuration options

Managed mode only supports the standard file options included in Protobuf. If you're using custom file options, you'll still need to include them in your .proto files.

See the buf.gen.yaml reference for a full explanation of managed mode's fields and usage.

Default behavior

When managed mode is enabled without any other settings, it uses the following defaults for all .proto files contained in the input, unless otherwise overridden:

  • cc_enable_arenas is not modified. Protobuf's default is true.
  • csharp_namespace is set to the package name with each package sub-part capitalized.
  • go_package_prefix does not modify go_package. Its default must be set to have an effect.
  • java_multiple_files is set to true. Protobuf's default is false.
  • java_outer_classname is set to the PascalCase-equivalent of the file name, removing the . for the .proto extension.
  • java_package_prefix is set to the package name with com. prepended to it.
  • java_string_check_utf8 is not modified. Protobuf's default is false.
  • objc_class_prefix is set to the uppercase first letter of each package sub-name, not including the package version, with the following rules:
    • If the resulting abbreviation is 2 characters, append X.
    • If the resulting abbreviation is 1 character, append XX.
    • If the resulting abbreviation is GPB, change it to GPX. GPB is reserved by Google for the Protocol Buffers implementation.
  • optimize_for is not modified. Protobuf's default is SPEED.
  • php_namespace is set to the package name with each package sub-name capitalized, with \ substituted for ..
  • php_metadata_namespace is set to the same value as php_namespace, with \GPBMetadata appended.
  • ruby_package is set to the package name with each package sub-name capitalized, with :: substituted for ..

For example, enabling managed mode for the acme/weather/v1/weather.proto file below with no other settings:

syntax = "proto3";

package acme.weather.v1;

// Messages, enums, etc.

sets its file options to the equivalent of this .proto file before it's sent to the compiler to generate code for the requested languages:

syntax = "proto3";

package acme.weather.v1;

option csharp_namespace = "Acme.Weather.V1";
option java_multiple_files = true;
option java_outer_classname = "WeatherProto";
option java_package = "com.acme.weather.v1";
option objc_class_prefix = "AWX";
option php_namespace = "Acme\Weather\V1";
option php_metadata_namespace = "Acme\Weather\V1\GPBMetadata";
option ruby_package = "Acme::Weather::V1";

// Messages, enums, etc.

Several of the standard file option fields can only be defined as per-file overrides: java_outer_classname, php_namespace, and php_metadata_namespace.

To see a complete file set illustrating managed mode, visit the managed-mode project.