Proto2 vs Proto3: Key Differences
Compare proto2 and proto3 syntax differences including required/optional fields, default values, enums, extensions, and migration strategies between versions.
Detailed Explanation
Proto2 vs Proto3 Comparison
Proto3 simplified the protobuf language by removing several proto2 features and changing default behaviors. Understanding the differences is essential when working with legacy schemas or migrating between versions.
// Proto2 syntax
syntax = "proto2";
message UserV2 {
required int32 id = 1;
required string name = 2;
optional string email = 3;
optional int32 age = 4 [default = 0];
repeated string tags = 5;
extensions 100 to 199;
}
// Proto3 syntax
// syntax = "proto3";
//
// message UserV3 {
// int32 id = 1;
// string name = 2;
// string email = 3;
// optional int32 age = 4;
// repeated string tags = 5;
// }
Feature Comparison
| Feature | Proto2 | Proto3 |
|---|---|---|
| Field presence | required, optional, implicit |
Implicit (all optional), explicit optional keyword |
| Default values | Custom defaults allowed | Fixed defaults only (0, false, "") |
required keyword |
Supported | Removed (considered harmful) |
| Unknown fields | Discarded by default | Preserved by default |
| Enum zero value | Not required | Must have zero value |
| Extensions | Supported | Removed (use Any instead) |
| Groups | Supported (deprecated) | Removed |
| Map fields | Not available | Added |
| JSON mapping | Basic | Full standard mapping |
Why required Was Removed
The required keyword in proto2 was identified as the largest source of backward-compatibility bugs. Once a field is marked required, it can never be removed without breaking all existing parsers. Proto3 treats all fields as optional, making schema evolution safer.
Field Presence in Proto3
In proto3, scalar fields do not track whether they were explicitly set. A field with value 0 could be "set to zero" or "not set at all." To distinguish these cases:
- Use wrapper types (
google.protobuf.Int32Value) - Use the
optionalkeyword (added back in proto3.15+) - Use a boolean companion field (e.g.,
bool has_age = 5;)
Migration Strategy
When migrating from proto2 to proto3:
- Remove all
requiredlabels - Remove custom
defaultvalues - Remove
extensions(replace withgoogle.protobuf.Anyor oneof) - Ensure all enums have a zero value
- Test with existing serialized data to verify compatibility
Use Case
Deciding which protobuf version to use for a new project, migrating legacy proto2 schemas to proto3, or understanding why a codebase uses specific protobuf patterns dictated by the version.