A field's type can be another message, whether it is defined in the same file, elsewhere in the package, or in an import, and a message can be declared inside another when the inner type only makes sense there.
It also gives teams one definition of a shared shape. If User, Event, and Office all use the same Location message, the code generated for every language agrees on what a location contains.
On the wire an embedded message is length-delimited, which means its bytes are preceded by their length. A decoder that lacks the inner schema can still skip the whole sub-message and read the fields after it.
message Result {
string url = 1;
string title = 2;
}
message SearchResponse {
Result top_result = 1;
}
{
"topResult": {
"url": "https://protobuf.com/",
"title": "Protobuf Explained"
}
}An embedded message travels as a block: a byte count up front, then the inner message's own bytes.
On the Bytes tab, click the outer segment: the byte count in front is what lets a decoder skip a sub-message it doesn't understand.
edition = "2024"; package demo.v1; message SearchResponse { Result top_result = 1; repeated Result results = 2; } message Result { string url = 1; string title = 2; }
Compiling the schema...
Next
Repeated Fields
Representing lists in Protobuf with repeated fields, and how packed encoding stores repeated scalars in a single length-prefixed block.