Enums, Nested & oneof
Enums: a named set of values
Section titled “Enums: a named set of values”An enum is a field that can only be one of a fixed set of named integers. It documents intent and prevents invalid states far better than a bare int32 or string.
enum Status { STATUS_UNSPECIFIED = 0; STATUS_ACTIVE = 1; STATUS_SUSPENDED = 2; STATUS_CLOSED = 3;}
message Account { int64 id = 1; Status status = 2;}The zero-value rule
Section titled “The zero-value rule”There is one rule you cannot skip: the first enum value must be 0, and it should mean “unspecified.” Because proto3 has no null for scalars, an unset enum field reads as its zero value. If 0 meant ACTIVE, every account that forgot to set a status would silently look active.
flowchart TB unset["field not set"] --> zero["reads as value 0"] zero --> good["0 = UNSPECIFIED → safe, obviously missing"] zero --> bad["0 = ACTIVE → dangerous, looks intentional"]
The convention (used across Google’s APIs) is to name it <ENUM>_UNSPECIFIED = 0. It gives you a clear “no value” state and reserves the meaningful values for explicit choices. Adding new enum values later is a safe, backward-compatible change — old clients simply treat unknown values as unknown.
Nested messages
Section titled “Nested messages”Messages can contain other messages. Nesting groups related data and lets you reuse a type, or scope a type to the message that owns it:
message Order { int64 id = 1;
message LineItem { // scoped to Order (Order.LineItem) string sku = 1; int32 quantity = 2; }
repeated LineItem items = 2; Address shipping = 3; // a top-level message reused here}Nest a type when it only makes sense inside its parent (Order.LineItem); keep it top-level when several messages share it (Address).
oneof: exactly one of several fields
Section titled “oneof: exactly one of several fields”A oneof says “at most one of these fields is set at a time.” Setting one clears the others, and the generated code gives you a clean way to check which is present.
message Notification { int64 user_id = 1;
oneof channel { string email = 2; string sms_number = 3; string push_token = 4; }}Here a notification goes out over exactly one channel. oneof models that “tagged union” precisely — far better than three nullable fields and a comment hoping only one is filled in. It’s also memory-efficient: the fields share storage.