Style Guide
This document provides a style guide for.proto files. By following theseconventions, you’ll make your protocol buffer message definitions and theircorresponding classes consistent and easy to read.
Enforcement of the following style guidelines is controlled viaenforce_naming_style.
Standard File Formatting
- Keep the line length to 80 characters.
- Use an indent of 2 spaces.
- Prefer the use of double quotes for strings.
File Structure
Files should be namedlower_snake_case.proto.
All files should be ordered in the following manner:
- License header (if applicable)
- File overview
- Syntax
- Package
- Imports (sorted)
- File options
- Everything else
Identifier naming styles
Protobuf identifiers use one of the following naming styles:
- TitleCase
- Contains uppercase letters, lowercase letters, and numbers
- The initial character is an uppercase letter
- The initial letter of each word is capitalized
- lower_snake_case
- Contains lowercase letters, underscores, and numbers
- Words are separated by a single underscore
- UPPER_SNAKE_CASE
- Contains uppercase letters, underscores, and numbers
- Words are separated by a single underscore
- camelCase
- Contains uppercase letters, lowercase letters, and numbers
- The initial character is an lowercase letter
- The initial letter of each subsequent word is capitalized
- Note: The style guide below does not use camelCase for anyidentifier in .proto files; the terminology is only clarified here sincesome language’s generated code may transform identifiers into thisstyle.
In all cases, treat abbreviations as though they are single words: useGetDnsRequest rather thanGetDNSRequest,dns_request rather thand_n_s_request.
Underscores in Identifiers
Don’t use underscores as the initial or final character of a name. Anyunderscore should always be followed by a letter (not a number or a secondunderscore).
The motivation for this rule is that each protobuf language implementation mayconvert identifiers into the local language style: a name ofsong_id in a.proto file may end up having accessors for the field which are capitalized asSongId,songId orsong_id depending on the language.
By using underscores only before letters, it avoids situations where names maybe distinct in one style, but would collide after they are transformed into oneof the other styles.
For example, bothDNS2 andDNS_2 would both transform into TitleCase asDns2. Allowing either of those names can be lead to painful situations when amessage is used only in some languages where the generated code keeps theoriginal UPPER_SNAKE_CASE style, becomes widely established, and then is onlylater used in a language where names are transformed to TitleCase where theycollide.
When applied, this style rule means that you should useXYZ2 orXYZ_V2rather thanXYZ_2 orXYZ_2V.
Packages
Use dot-delimited lower_snake_case names as package names.
Multi-word package names may be lower_snake_case or dot.delimited (dot-delimitedpackage names are emitted as nested packages/namespaces in most languages).
Package names should attempt to be a short but unique name based on the projectname. Package names should not be Java packages (com.x.y); instead usex.yas the package and use thejava_package option as needed.
Message Names
Use TitleCase for message names.
messageSongRequest{}Field Names
Use snake_case for field names, including extensions.
Use pluralized names for repeated fields.
stringsong_name=1;repeatedSongsongs=2;Oneof Names
Use lower_snake_case for oneof names.
oneofsong_id{stringsong_human_readable_id=1;int64song_machine_id=2;}Enums
Use TitleCase for enum type names.
Use UPPER_SNAKE_CASE for enum value names.
enumFooBar{FOO_BAR_UNSPECIFIED=0;FOO_BAR_FIRST_VALUE=1;FOO_BAR_SECOND_VALUE=2;}The first listed value should be a zero value enum and have the suffix of either_UNSPECIFIED or_UNKNOWN. This value may be used as an unknown/default valueand should be distinct from any of the semantic values you expect to beexplicitly set. For more information on the unspecified enum value, seethe Proto Best Practices page.
Enum Value Prefixing
Enum values are semantically considered to not be scoped by their containingenum name, so the same name in two sibling enums is not allowed. For example,the following would be rejected by protoc since theSET value defined in thetwo enums are considered to be in the same scope:
enumCollectionType{COLLECTION_TYPE_UNSPECIFIED=0;SET=1;MAP=2;ARRAY=3;}// Won't compile - `SET` enum name will clash// with the one defined in `CollectionType` enum.enumTennisVictoryType{TENNIS_VICTORY_TYPE_UNSPECIFIED=0;GAME=1;SET=2;MATCH=3;}Name collisions are a high risk when enums are defined at the top level of afile (not nested inside a message definition); in that case the siblings includeenums defined in other files that set the same package, where protoc may not beable to detect the collision has occurred at code generation time.
To avoid these risks, it is strongly recommended to do one of:
- Prefix every value with the enum name (converted to UPPER_SNAKE_CASE)
- Nest the enum inside a containing message
Either option is enough to mitigate collision risks, but prefer top-level enumswith prefixed values over creating a message simply to mitigate the issue. Sincesome languages don’t support an enum being defined inside a “struct” type,preferring prefixed values ensures a consistent approach across bindinglanguages.
Services
Use TitleCase for service names and method names.
serviceFooService{rpcGetSomething(GetSomethingRequest)returns(GetSomethingResponse);rpcListSomething(ListSomethingRequest)returns(ListSomethingResponse);}Things to Avoid
Required Fields
Required fields are a way to enforce that a given field must be set when parsingwire bytes, and otherwise refuse to parse the message. The required invariant isgenerally not enforced on messages constructed in memory. Required fields wereremoved in proto3. Proto2required fields that have been migrated to editions2023 can use thefield_presence feature set toLEGACY_REQUIRED toaccommodate.
While enforcement of required fields at the schema level is intuitivelydesirable, one of the primary design goals of protobuf is to support long termschema evolution. No matter how obviously required a given field seems to betoday, there is a plausible future where the field should no longer be set (e.g.anint64 user_id may need to migrate to aUserId user_id in the future).
Especially in the case of middleware servers that may forward messages that theydon’t really need to process, the semantics ofrequired has proven too harmfulfor those long-term evolution goals, and so is now very strongly discouraged.
SeeRequired is Strongly Deprecated.
Groups
Groups is an alternate syntax and wire format for nested messages. Groups areconsidered deprecated in proto2, were removed from proto3, and are converted toa delimited representation in edition 2023. You can use a nested messagedefinition and field of that type instead of using the group syntax, using themessage_encodingfeature for wire-compatibility.
Seegroups.