Skip to content

Send a field set to its zero value, an int at 0 or a string at "", and under implicit presence it looks exactly like a field nobody touched. That's the question presence answers. Can a reader tell those two cases apart? Edition 2024 gives every field explicit presence by default, so the answer is yes, a value of 0 and an absent field are different states. Switch a field to IMPLICIT and that distinction disappears. A zero stops getting written at all, and a reader has no way to tell it from a field that was never set.

These two schemas differ by one word. Both messages below have every field set to its zero value, which is the only point where the difference shows.

Explicit presence
edition = "2024";

package demo.v1;

option features.field_presence = EXPLICIT;

message Settings {
  string label = 1;
  int32 retries = 2;
  bool verbose = 3;
}
JSON
{
  "label": "",
  "retries": 0,
  "verbose": false
}

Every field tracks presence, so a zero is a value it holds and gets written out.

Implicit presence
edition = "2024";

package demo.v1;

option features.field_presence = IMPLICIT;

message Settings {
  string label = 1;
  int32 retries = 2;
  bool verbose = 3;
}
JSON
{}

No field tracks presence, so every zero means the same thing as absent and there is nothing left to write.

The same zero value either costs two bytes or vanishes entirely, depending on the field's presence.

The explicit field writes its zero so a reader knows it was set. The implicit field's zero disappears.

schema.proto
edition = "2024";

package demo.v1;

message Counter {
  // Edition 2024 default: explicit presence.
  int32 explicit_count = 1;
  int32 implicit_count = 2 [features.field_presence = IMPLICIT];
}
Input JSON (editable)
{
  "explicitCount": 0,
  "implicitCount": 0
}
ProtoJSON

Compiling the schema...

Further Reading

Next

Required Fields

Why Protobuf dropped the required keyword, what went wrong with it, and how to enforce required semantics today with validation instead of the wire format.