How .proto files are formatted
The engine is clang-format (WASM, proto mode). clang-format is best known for C and C++, but it has a dedicated Protocol Buffers mode — the same one used by many Google and gRPC repositories and by editor plugins that format .proto files on save.
In proto mode it:
- puts each field, enum value,
optionandrpcon its own line - indents nested messages, enums and
oneofgroups - normalises spacing around
=in field numbers and options - formats
rpc Method(Request) returns (stream Response)signatures consistently - re-wraps long field options and comments at the line width
It works for proto2 and proto3 files and for edition-based schemas, since the layout rules do not depend on the syntax version.
A tidy schema matters more for protobuf than for most formats because the .proto file is the contract between services. Field numbers that line up one per line make it easy to spot a reused number or a gap left by a deleted field, which is exactly what reviewers need to check before a change ships to clients that cannot be updated at the same time.
The Style option, indent and width
Style chooses clang-format’s base preset: Google (the default), LLVM, Chromium, Mozilla, WebKit, Microsoft or GNU. For protobuf files the presets mostly differ in small things, such as whether a very short message like message Empty { string id = 1; } may stay on one line and whether spaces appear inside the brackets of field options ([json_name = "x"] versus [ json_name = "x" ]). Google is the right choice for most gRPC projects because Google’s own style guide for protos is written against it.
Whatever preset you pick, the toolbar’s indent replaces the preset’s IndentWidth, and the line-width control sets ColumnLimit. Choosing tabs switches to tab indentation.
Shortcuts: Ctrl/Cmd+Enter formats, Ctrl/Cmd+Shift+C copies, Ctrl/Cmd+K opens the command palette. There is no minified form of a schema, so Ctrl/Cmd+Shift+M is not used here.
It formats; it does not compile
This is the most important thing to know: clang-format is a layout tool. It tokenises the file and reprints it, but it does not check that the schema is valid. A missing semicolon, a duplicate field number or an unknown type will not produce an error. Instead the output looks subtly wrong — two statements merged on one line, or a stray brace at the left margin — and that is your cue to look closer.
To validate a schema, run protoc or buf lint, which also catch style issues such as field names that are not lower_snake_case and enum values without a type prefix.
Comments, including the // documentation comments above messages and RPCs, are kept and re-wrapped only if they exceed the width. Import order is left as written. Use the JSON formatter to read the JSON encoding of a message.
Examples
oneof, field options and reserved, LLVM style
The LLVM preset keeps the one-field message on a single line and adds spaces inside the option brackets.
syntax="proto3";package billing.v1;
message Payment{string id=1;oneof method{Card card=2;BankTransfer bank=3;}int64 amount_cents=4 [json_name="amountCents"];reserved 5,6;reserved "legacy_ref";}
message Card{string last4=1;int32 exp_month=2;int32 exp_year=3;}
message BankTransfer{string iban=1;}syntax = "proto3";
package billing.v1;
message Payment {
string id = 1;
oneof method {
Card card = 2;
BankTransfer bank = 3;
}
int64 amount_cents = 4 [ json_name = "amountCents" ];
reserved 5, 6;
reserved "legacy_ref";
}
message Card {
string last4 = 1;
int32 exp_month = 2;
int32 exp_year = 3;
}
message BankTransfer { string iban = 1; }
gRPC service with comments
Comments stay above the RPC they document, and the option block inside an rpc is expanded.
// Inventory service
service Inventory{
// Streams stock updates for one warehouse.
rpc WatchStock(WatchStockRequest)returns(stream StockEvent){option deprecated=false;}
rpc Adjust(AdjustRequest)returns(AdjustResponse);}// Inventory service
service Inventory {
// Streams stock updates for one warehouse.
rpc WatchStock(WatchStockRequest) returns (stream StockEvent) {
option deprecated = false;
}
rpc Adjust(AdjustRequest) returns (AdjustResponse);
}
Enum and map fields, Google style
Each enum value and field gets a line; the map type keeps its compact form.
syntax="proto3";
enum Status{STATUS_UNSPECIFIED=0;STATUS_ACTIVE=1;STATUS_SUSPENDED=2;}
message Account{string id=1;Status status=2;map<string,string> labels=3;repeated string emails=4;}syntax = "proto3";
enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_ACTIVE = 1;
STATUS_SUSPENDED = 2;
}
message Account {
string id = 1;
Status status = 2;
map<string, string> labels = 3;
repeated string emails = 4;
}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Two statements appear on one line in the output | A semicolon is missing, for example after syntax = "proto3". clang-format does not report it; it simply joins the lines. | Add the semicolon and format again. Run protoc or buf lint to catch this class of mistake reliably. |
A closing brace is printed at the start of a line after the last message | The braces are unbalanced: there is one } more than {. | Remove the surplus brace. The formatter does not flag it because it never validates the grammar. |
A message ends without its closing brace in the output | A } is missing, so everything after it is treated as part of the same message. | Close the message where it should end; check nested messages and enums first. |
Field options gain or lose spaces inside the brackets | This is a style difference, not an error: some presets put spaces inside [ ]. | Switch the Style option to Google if you want [json_name = "x"] without inner spaces. |
Frequently asked questions
Which style should I choose for gRPC projects?
Google. It is the default here and matches the style used in most published .proto files and in the protobuf documentation.
Why was my invalid .proto not rejected?
clang-format only rearranges tokens and never checks the protobuf grammar. Use protoc or buf lint to validate a schema.
Does it work with proto2 and editions?
Yes. The layout rules are the same for proto2, proto3 and edition-based files.
Will it reorder fields or renumber them?
No. Field order, field numbers and import order are left exactly as written; only whitespace and line breaks change.