Skip to content

Any is for dynamic Protobuf messages, cases where a schema exists but isn't known until runtime. Sometimes the data itself is more dynamic than that. Maybe it's arbitrary structured JSON you don't want to model as its own schema. Maybe it's completely dynamic, like a schema-less JSON object. Either way, that's what google.protobuf.Value and google.protobuf.Struct are for.

A Value can be a null, a number, a string, or a boolean. It can also be a recursive struct, or a list of other values. Line those options up against JSON's own type system, null, number, string, boolean, object, array, and they match one for one.

Use it sparingly. Every field typed as Value or Struct gives up the strong typing that's the reason you reached for Protobuf in the first place. Still, it earns its keep integrating with a schemaless NoSQL database, or passing around a metadata blob nobody wants to type out.

Any, Value, and Struct all fall under Well-Known Types. The Types reference lists the rest, including Timestamp and Duration.

Compare with a schema field: here the names theme, retries, and beta are all in the payload.

schema.proto
edition = "2024";

package demo.v1;

import "google/protobuf/struct.proto";

message Config {
  google.protobuf.Struct settings = 1;
}
Input JSON (editable)
{
  "settings": {
    "theme": "dark",
    "retries": 3,
    "beta": true
  }
}
ProtoJSON

Compiling the schema...

Next

Editions

What Protobuf editions are, how they replace proto2 and proto3 syntax, and how features migrate schemas incrementally without breaking the wire format.