A protobuf formatter for .proto files
Protocol Buffers schemas define the messages and gRPC services that other code is generated from, so they are read often and changed carefully. This protobuf formatter uses clang-format's Protocol Buffers mode to indent messages, enums and services, put one field per line, and space field assignments and options consistently. It works for proto2, proto3 and editions syntax because it formats tokens rather than validating semantics.
Example
syntax="proto3";package shop.v1;import "google/protobuf/timestamp.proto";option go_package="example.com/shop/v1;shopv1";enum Status{STATUS_UNSPECIFIED=0;STATUS_PAID=1;}message Order{string id=1;repeated LineItem items=2;google.protobuf.Timestamp created_at=3;map<string,string> labels=4;oneof payment{string card_token=5;string voucher=6;}}service Orders{rpc Get(GetOrderRequest)returns(Order);rpc Watch(WatchRequest)returns(stream Order);}
syntax = "proto3";
package shop.v1;
import "google/protobuf/timestamp.proto";
option go_package = "example.com/shop/v1;shopv1";
enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_PAID = 1;
}
message Order {
string id = 1;
repeated LineItem items = 2;
google.protobuf.Timestamp created_at = 3;
map<string, string> labels = 4;
oneof payment {
string card_token = 5;
string voucher = 6;
}
}
service Orders {
rpc Get(GetOrderRequest) returns (Order);
rpc Watch(WatchRequest) returns (stream Order);
}
Every field and enum value gets its own line, = is spaced, the map<string, string> type gets a space after the comma, and returns (stream Order) is spaced as in the official examples.
Protobuf style guide essentials
The official Protocol Buffers style guide covers naming as well as layout. A formatter only handles layout, so it is worth checking the rest by eye:
- Indentation: 2 spaces (the Google preset's default) and lines up to 80 characters.
- Messages, enums and services in
PascalCase; fields inlower_snake_case; enum values inUPPER_SNAKE_CASEprefixed with the enum name. - Zero value: the first enum value should be
_UNSPECIFIED = 0, because proto3 uses zero as the default. - Repeated fields get plural names (
items, notitem). - Packages are lowercase and often versioned (
shop.v1).
What the formatter will not do
- Renumbering fields: field numbers are part of the wire format and are never changed. Reusing or changing a number breaks compatibility with existing data.
- Reordering: declarations stay in the order you wrote them.
- Validation: duplicate field numbers, unknown types or missing imports are not reported. Use
protocorbuf lintfor that.
Comments become documentation
Comments placed directly above a message, field, enum value or RPC are copied by protoc into the generated code for most languages, where they show up as doc comments in IDEs. The formatter keeps them attached to the declaration below, so it is worth writing them in full sentences and keeping them next to the element they describe.
Options
Style defaults to Google, which matches the protobuf style guide's 2-space indentation. Indent can be set to 4 spaces if your repository uses it. Column limit controls when long option lists or comments wrap; the style guide recommends 80, while this tool starts at 100. Short messages may be collapsed onto one line by some presets (for example LLVM prints message A { int32 x = 1; }), so stay with Google if you always want one field per line.
Common syntax mistakes
- Missing semicolons after fields or
syntax = "proto3"lead to broken indentation in the output. - Field names with hyphens are invalid; use underscores.
requireddoes not exist in proto3;optionalis allowed again since protobuf 3.15.
Working with the JSON representation of your messages? Format it with the JSON Formatter, or derive a JSON Schema from a sample using JSON to JSON Schema. Formatting runs in your browser.