Skip to content

Whether a field holding its zero value reaches the wire at all is a per-field choice.

A field with implicit presence isn't written to the wire at all when it holds its zero value (0, empty string, false). That saves the tag and the payload for every field left at its default. A reader can't tell "set to 0" from "never set."

Explicit presence keeps that distinction. Once set, the field gets written even when its value is the zero value, and generated code can offer a has_field() check. Message fields and members of a oneof always have explicit presence, whatever the file is configured to do.

Presence is a schema feature. Edition 2024 defaults the fields you can configure to EXPLICIT presence. Set features.field_presence = IMPLICIT; on a file, message, or field to leave default-valued fields off the wire instead.

Older syntaxes: Before editions, the default came from the syntax you picked. Proto2 scalar fields were explicit. Proto3 scalar fields were implicit unless marked optional. Message fields and oneof members were explicit in both. Editions replace that split with a feature you set per field.

IMPLICIT PRESENCE
Schema Definition
int32 count = 1 [features.field_presence = IMPLICIT];
Assigned Value
0
OMITTED
Wire Representation
(Zero Bytes)

Omitted from the wire whenever it holds the zero value, so a reader cannot tell this from never set.

EXPLICIT PRESENCE
Schema Definition
int32 count = 1;
Assigned Value
0 (set)
SERIALIZED
Wire Representation
08
Tag
00
Data

Edition 2024's default. Once set, the field is written even when the value is zero.

Further Reading

Next

Parse Loop

The Protobuf parse loop, field by field: read a tag, dispatch on the wire type, consume the value, and repeat until the bytes run out.