Managed mode#
Plugins use language-specific file options (Java’s java_package, Go’s go_package, C#’s csharp_namespace, and so on) to decide where output goes and what it’s named.
Hard-coding those options inside producer-owned .proto files makes the schema language-aware: every consumer is stuck with whatever the producer chose, and the producer has to make decisions for every downstream language.
Managed mode moves those options out of .proto files and into buf.gen.yaml.
The same .proto schema then produces code in different namespaces for different consumers, with the producer carrying no language-specific options at all.
The same generated output now comes from two added lines in buf.gen.yaml instead of three options on every .proto file.
Enable managed mode#
Set managed.enabled: true in buf.gen.yaml:
version: v2
managed:
enabled: true
plugins:
- remote: buf.build/protocolbuffers/java
out: gen/proto/java
If managed mode’s default behavior matches what you need, no further configuration is required.
For specific overrides, see Override the defaults.
For an annotated example covering every key, see the buf.gen.yaml reference.
Default behavior#
When managed mode is enabled, plugins receive these file-option values at generation time, derived from the Protobuf package.
The examples in this section all share the same .proto schema and workspace:
workspace_root
├── buf.gen.yaml
├── buf.yaml
└── proto
└── acme
└── weather
└── v1
└── weather.proto
syntax = "proto3";
package acme.weather.v1;
enum Condition {
CONDITION_UNSPECIFIED = 0;
CONDITION_SUNNY = 1;
CONDITION_RAINY = 2;
}
message GetWeatherRequest {
float latitude = 1;
float longitude = 2;
}
message GetWeatherResponse {
float temperature = 1;
Condition conditions = 2;
}
service WeatherService {
rpc GetWeather (GetWeatherRequest) returns (GetWeatherResponse);
}
C##
C# supports csharp_namespace and csharp_namespace_prefix.
Files go to out directly (no directory restructuring); the namespace is derived from the package:
To prefix the derived namespace, set csharp_namespace_prefix:
C++#
Managed mode supports cc_enable_arenas, but Protobuf enables arenas by default and modern generators ignore the option’s value.
Setting it changes the descriptor byte representation but has no runtime effect.
Go#
Go has no default; you must set one of go_package or go_package_prefix for any plugin that depends on the option (protoc-gen-go, protoc-gen-go-grpc, and so on).
The two options are mutually exclusive: if both match a file, the last rule wins.
go_package_prefix is the common choice because it preserves the package-derived directory layout:
go_package sets the entire path, replacing the package-derived directories:
These examples assume protoc-gen-go runs with paths=import (the default).
For Go’s import-path conventions, see the Protobuf Go documentation.
Java#
Managed mode applies these defaults for Java:
| Option | Default |
|---|---|
java_multiple_files |
true |
java_outer_classname |
PascalCase of the .proto filename |
java_package |
<java_package_prefix>.<proto_package>, prefixed with com |
java_package_prefix |
com |
java_package_suffix |
(none) |
java_string_check_utf8 |
false |
The default java_package is the Protobuf package with a com. prefix:
The combination of java_package_prefix and java_package_suffix is the common override.
Both apply together to produce <prefix>.<proto_package>.<suffix>:
java_package is mutually exclusive with the prefix/suffix pair: if all three rules match a file, last-wins applies, with one exception. When java_package_prefix and java_package_suffix are the last matching rules and a java_package rule matches earlier, the file gets <prefix>.<proto_package>.<suffix> rather than the earlier java_package value.
Objective-C#
Managed mode supports objc_class_prefix, which controls the class prefix for all generated Objective-C classes.
The default value is derived from the Protobuf package: take the first letter of each component, uppercase it, pad to three letters with X if shorter, and replace the literal GPB with GPX.
For acme.weather.v1, the default prefix is AWX.
To set a specific prefix:
PHP#
PHP supports php_namespace, php_metadata_namespace, and php_metadata_namespace_suffix.
Set at most one; if multiple match, last-wins applies.
Defaults:
php_namespace: package components in PascalCase joined by\(reserved keywords get a trailing_). Foracme.weather.v1:Acme\Weather\V1.php_metadata_namespace:<php_namespace>\GPBMetadata.php_metadata_namespace_suffix: no default; if set, replaces theGPBMetadatasegment.
The common override is to set php_namespace directly:
Ruby#
Ruby supports ruby_package and ruby_package_suffix.
Neither changes directory layout; both change the nesting of Ruby modules in generated files.
ruby_package_suffix is Buf-specific managed-mode sugar (it isn’t a stock Protobuf option); it modifies ruby_package by appending the suffix.
The default nests modules from the package:
To replace the derived value entirely, set ruby_package:
Swift#
Swift supports swift_prefix, which controls the prefix on generated structs.
There’s no default; you must set a value if any plugin depends on the option.
Override the defaults#
Use managed.override to set a file option’s value for some or all matching files.
Each rule names a file_option (or field_option) and a value. Optional keys narrow which files the rule applies to:
version: v2
managed:
enabled: true
override:
# Default for all files: prefix go_package with the org's import path.
- file_option: go_package_prefix
value: company.com/proto
# For one specific module, override the prefix to a different value.
- file_option: go_package_prefix
module: buf.build/acme/weather
value: x/y/z
# For one specific path, set go_package directly. This wins over the
# earlier go_package_prefix rule for matching files.
- file_option: go_package
path: special/path/
value: special/value/package/v1
Match by module, path, file, or field#
A rule applies only when every specified key matches a file. The available keys:
| Matcher | Selects |
|---|---|
module: |
A BSR-style module name (buf.build/owner/name). Local-only modules that haven’t been published need path: matching instead. |
path: |
A directory or single .proto file relative to the workspace root. |
file_option: |
A single file option (java_package, go_package_prefix, and so on). |
field: |
A fully qualified field name like package.Message.field. |
field_option: |
A single field option (only jstype today). |
Precedence#
Rules evaluate in order. The last rule that matches a given (option, file) pair wins. Order more general rules first, then specific overrides:
managed:
enabled: true
override:
- file_option: java_package_prefix
value: net # Default for everything.
- file_option: java_package_prefix
module: buf.build/acme/petapis
value: com # Petapis files only.
- file_option: java_package_suffix
module: buf.build/acme/petapis
value: com # Same module: prefix and suffix combine.
- file_option: java_package
path: foo/bar/baz.proto
value: com.x.y.z # One specific file: overrides everything above.
Disable managed mode for specific inputs#
managed.disable keeps managed mode from modifying particular inputs.
A common case is dependencies you don’t own:
version: v2
managed:
enabled: true
disable:
# Don't modify any file in googleapis.
- module: buf.build/googleapis/googleapis
disable rules use the same keys as override. Common shapes:
managed:
enabled: true
disable:
# Disable one option globally.
- file_option: csharp_namespace
# Disable everything for a path.
- path: foo/v1
# Disable a specific option for a path within a specific module.
- module: buf.build/acme/weather
path: foo/v1
file_option: java_package
# Disable a field option for one field.
- field: foo.bar.Baz.field_name
field_option: jstype
When a file matches both disable and override for the same option, disable wins; the override doesn’t apply.
Field options#
The only field option managed mode supports is jstype, which controls how a JavaScript runtime materializes 64-bit integer fields.
Accepted values: JS_NORMAL, JS_NUMBER, JS_STRING.
There’s no default; the rule applies only where it matches.
version: v2
managed:
enabled: true
override:
# Set jstype = JS_NORMAL for every compatible field in a module.
- field_option: jstype
module: buf.build/acme/paymentapis
value: JS_NORMAL
# Set jstype for one specific field.
- field_option: jstype
field: package.Message.field
value: JS_STRING
For the underlying field-option semantics, see the JSType definition in descriptor.proto.
Other file options#
Managed mode supports a few file options that aren’t language-scoped.
optimize_for#
Sets the optimize_for file option globally.
There’s no default; the rule applies only when set.
Accepted values: SPEED, CODE_SIZE, LITE_RUNTIME.
A few constraints worth knowing:
- Not every code generator honors
optimize_for. Java’s does; the Go and C# generators don’t. - If
a.protoimportsb.protoandb.protoisLITE_RUNTIME, thena.protomust also beLITE_RUNTIMEor it won’t compile. - In Java,
SPEEDandLITE_RUNTIMEproduce equivalent code, butCODE_SIZEis meaningfully different.
Troubleshooting#
Go imports for dependencies are wrong after enabling managed mode#
If managed mode is rewriting go_package for a dependency you don’t own, exclude it:
version: v2
managed:
enabled: true
disable:
- file_option: go_package_prefix
module: buf.build/dependency/module
googleapis resolves to a local import path instead of the BSR#
Managed mode is applying go_package_prefix to files inside buf.build/googleapis/googleapis. Disable that specific rewrite:
version: v2
managed:
enabled: true
disable:
- file_option: go_package_prefix
module: buf.build/googleapis/googleapis
Migrating from v1#
The shape of managed: changed substantially between v1 and v2.
For step-by-step migration, see the v2 configuration migration guide.