Skip to content

Descriptors

Descriptors are Protobuf schemas represented as Protobuf data. They power reflection, dynamic decoding, validation, and compiler plugin input.

Schemas Describing Schemas

When you compile a schema, the compiler doesn't just generate code. It can also output a binary representation of the schema itself, called a FileDescriptorSet. Both compilers will produce one: buf build -o descriptor.binpb or protoc --descriptor_set_out.

This FileDescriptorSet is itself a Protobuf message. Google defines a schema (descriptor.proto) that describes how to represent .proto files. This means you can use Protobuf tools to read and analyze Protobuf schemas dynamically at runtime. Buf's descriptors reference is a deep dive into how they work.

Why is this useful?

Dynamic Decoding

Tools like this web explorer use descriptors to decode arbitrary binary data without generating static code.

Validation

Complex rule engines (like protovalidate) use descriptors to apply constraints dynamically.

Code Generation

Code generator plugins receive these descriptors as input. This is how every custom generator is built, and why the same plugin binary works under both buf generate and protoc.

Server Reflection

A server can hand out its own descriptors over the wire, so a client can call it knowing nothing in advance. buf curl uses this to invoke any reflection-enabled gRPC or Connect endpoint with no .proto files on your disk.

descriptor.proto (snippet)
// The schema that describes a schema
message FileDescriptorSet {
  repeated FileDescriptorProto file = 1;
}

message FileDescriptorProto {
  optional string name = 1;
  optional string package = 2;
  repeated DescriptorProto message_type = 4;
  repeated EnumDescriptorProto enum_type = 5;
  // ...
}

message DescriptorProto {
  optional string name = 1;
  repeated FieldDescriptorProto field = 2;
  // ...
}

Try editing the schema below to see how the generated FileDescriptorSet changes in real-time.

Schema editor (.proto)
edition = "2023";

package demo.v1;

import "buf/validate/validate.proto";

message User {
  string id = 1 [json_name = "uid"];
  string name = 2;
  uint32 age = 3 [(buf.validate.field).uint32.lt = 150];
  Role role = 4;

  enum Role {
    ROLE_UNSPECIFIED = 0;
    ROLE_USER = 1;
    ROLE_ADMIN = 2;
  }
}
Valid
Descriptor output

Fix compilation errors
to view descriptor