Skip to content

Protobuf Naming Convention Best Practices: The Importance of Naming Conventions as Seen from Code Reviews of 50+ Proto Files ​

Protobuf Naming Convention Best Practices: An Illustration of the Importance of Naming Conventions from Code Review of 50+ Proto Files

Introduction: An Experience I'd Rather Not Recall ​

During a Code Review, I came across an old project with more than 30 Proto files alone. You think the most painful part is understanding the business logic? No. The most painful part is—You can't understand what these Proto files themselves are saying.

File names use mixed case; the same field is called logicalname, in another file it is called logicalName, just call it directly in the third file LogicalName Enum values are sometimes all uppercase, sometimes camelCase, and sometimes prefixed.k.Request and Response may be nested in some message Internally, or possibly at the top level—there is no pattern whatsoever.

During cross-team collaboration, a serialization/deserialization failure caused by inconsistent casing in field names took two full days to troubleshoot.

This is not a joke; it's a personal experience.

This article summarizes Protobuf naming conventions based on observations from this Code Review. I hope those who come after will not have to go through the same pain.

Statement: Every Git Commit conveys your professionalism. ​

I hope you show your professionalism during team development, instead of writing a bunch of garbage code that makes anyone who comes across it curse!

1. Why do we need a unified naming convention? ​

1.1 Code is written for people to read ​

Protobuf files are interface contracts and a bridge for collaboration between teams. A Proto file with chaotic naming forces readers to spend extra effort understanding what the name actually means.

1.2 A Real Lesson ​

During a cross-team integration test, the field name sent by the client was logicalname, the field name parsed by the server is logicalName. Protocol Buffers is case-sensitive, and as a result—the fields never get values; it took two days of troubleshooting to discover that it was a naming inconsistency.

If there were a unified naming convention, this problem would not have occurred at all.

II. File Naming Conventions ​

Specification requirements ​

  • Use all lowercase

  • Use underscore Separate multiple words

  • One Service corresponds to one file.

Correct example ​

user.proto
product.proto
product_detail.proto
common.proto

Error example ​

mKfs.proto          // Mixed case
getUser.proto       // camel hump
productdetail.proto // Two words are not separated by an underscore

Why do it this way? ​

Different operating systems handle filename case differently (Linux is case-sensitive, Windows is not), and using all lowercase can avoid unexpected problems during cross-platform collaboration.

III. Message Naming Conventions ​

Specification requirements ​

  • Use Pascal case naming convention (PascalCase)

  • Request/Response must be named in pairs

  • The name should be semantically clear.

Correct example ​

protobuf
message CreateUserRequest {}
message CreateUserResponse {}

message GetProductRequest {}
message GetProductResponse {}

message ServiceConfig {}
message NodeInfo {}

Incorrect example ​

protobuf
message createUserRequest {}    // start with lowercase
message create_user_req {}      // underscore-separated
message CreateUserResp {}       // Response abbreviation is not standardized

Request/Response pairing principle ​

Every RPC method should have corresponding Request and Response messages:

protobuf
service UserService {
    rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
    rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
    rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
}

IV. Field Naming Conventions ​

Specification requirements ​

  • Use lowercase + underscore-separated (snake_case)

  • The name should clearly express the meaning of the field.

  • Avoid abbreviations (unless they are widely recognized).

Correct example ​

protobuf
message NodeInfo {
    string node_name = 1;
    uint32 node_id = 2;
    bool use_absolute_path = 3;
    string access_mode = 4;
}

Incorrect example ​

protobuf
message NodeInfo {
    string NodeName = 1;          // camel hump
    string nodename = 2;          // all lowercase, no separators
    string nodeName = 3;          // camel hump
    bool useAbsPath = 4;          // CamelCase + Abbreviation
}

Why does inconsistent capitalization of field names cause problems? ​

Protocol Buffers field names (the names corresponding to tags) are case-sensitive during serialization. If the client uses logicalname, server-side parsing logicalName, Although the tag numbers are the same, the field access methods in the generated code differ, which may prevent data from being populated correctly.

More seriously, when using JSON serialization (such as gRPC's JSON mapping), field names are directly exposed in the API, and inconsistent capitalization can lead to interface incompatibility.

V. Enum Naming Convention ​

Specification requirements ​

  • Enum type name usage UpperCamelCase (PascalCase)

  • Enum value usage All uppercase + underscores (UPPER_SNAKE_CASE)

  • Enumeration values must start at 0

Correct example ​

protobuf
enum NodeType {
    NODE_TYPE_UNSPECIFIED = 0;
    NODE_TYPE_PRIMARY = 1;
    NODE_TYPE_SECONDARY = 2;
}

enum Status {
    STATUS_UNSPECIFIED = 0;
    STATUS_ACTIVE = 1;
    STATUS_INACTIVE = 2;
}

Error example ​

protobuf
enum nodeType {          // Type name lowercase
    PRIMARY = 0;
    SECONDARY = 1;
}

enum TaskType {
    kPreLoad = 1;        // Enum values do not start at 0.
    kAdd = 2;            // Prefix confusion
}

Enum value naming conventions ​

To avoid enum values conflicting between different enums, it is recommended to add a type prefix to enum values:

protobuf
enum NodeType {
    NODE_TYPE_UNSPECIFIED = 0;
    NODE_TYPE_PRIMARY = 1;
    NODE_TYPE_SECONDARY = 2;
}

enum TaskType {
    TASK_TYPE_UNSPECIFIED = 0;
    TASK_TYPE_IMPORT = 1;
    TASK_TYPE_EXPORT = 2;
}

VI. Service and RPC Method Naming Conventions ​

Specification requirements ​

  • Service name usage Upper Camel Case (PascalCase)

  • RPC method name uses Upper camel case (PascalCase)

  • Method names should reflect the operation intent.

Correct example ​

protobuf
service UserService {
    rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
    rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
    rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse);
}

Error example ​

protobuf
service userService {               // service name starts with lowercase
    rpc listUsers(...)              // Method names start with lowercase.
    rpc CreateUser(...)             // mixed use
    rpc delete_user(...)            // underscore
}

Common method verbs ​

verbPurposeExample
GetGet a single resourceGetUser
ListGet resource listListUsers
CreateCreate resourceCreateUser
UpdateUpdate resourcesUpdateUser
DeleteDelete resourceDeleteUser

VII. File Organization Specifications ​

7.1 One Service, One File ​

Split different Services into separate files to facilitate maintenance and team collaboration:

proto/
├── common.proto          // Public type
├── user.proto
├── product.proto
└── order.proto

7.2 Put common types in separate files ​

Types shared by multiple Services (such as common response structures and base enums) should be placed in a separate file:

protobuf
// common.proto
message CommonResponse {
    int32 code = 1;
    string message = 2;
}

Other documents passed import Quote:

protobuf
// user.proto
import "common.proto";

7.3 Nested Request/Response Is Prohibited ​

Incorrect example:

protobuf
message CreateUserRequest {
    string name = 1;

    message CreateUserResponse {    // Response is nested inside Request
        CommonResponse result = 1;
    }

    service UserService {
        rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
    }
}

Correct example:

protobuf
message CreateUserRequest {
    string name = 1;
}

message CreateUserResponse {
    CommonResponse result = 1;
}

service UserService {
    rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
}

7.4 Reasonable Boundaries for Nesting ​

Although Proto supports message and enum Nested, but suggest:

  • internal enum: If an enum is only used inside a certain Message, it can be nested.

  • Internal message: Avoid it as much as possible unless it is a strongly dependent auxiliary type.

  • Service and Request/Response: Nesting is prohibited; must be defined at the top level

VIII. How to implement naming conventions ​

8.1 Introducing the Lint Tool ​

buf is currently the most popular Protobuf Lint tool:

yaml
# buf.yaml
version: v1
lint:
  use:
    - DEFAULT

protolint is another option:

yaml
# .protolint.yaml
lint:
  rules:
    no:
      - MESSAGE_NAMES_UPPER_CAMEL_CASE

8.2 Code Review Mandatory Checklist Items ​

In Code Review, changes to Proto files must be checked:

  • Whether the filename is all lowercase + underscores

  • Is the Message name in UpperCamelCase?

  • Whether field names are lowercase + underscore

  • Whether enum values are all uppercase + underscores

  • Does enumeration start from 0?

  • Are Request/Response paired?

  • Should Service and methods use PascalCase?

  • Is there unnecessary nesting?

8.3 Develop team standards documentation ​

Organize the above specifications into a team document as a unified standard for writing Proto files.

9. Checklist Quick Reference Table ​

Check itemSpecification
Filenamesnake_case.proto
Message NamePascalCase
Field namesnake_case
enumeration type namePascalCase
enum valueUPPER_SNAKE_CASE
Service NamePascalCase
RPC method namePascalCase
枚举起始值Must be 0
Request/ResponseTop-level definitions only; nesting is prohibited.
ServiceTop-level definition; nesting is prohibited.

Summary ​

Protobuf naming conventions may seem like a minor detail, but in large cross-team collaborative projects, consistency is productivity.

A single field name case mismatch can cost two days of troubleshooting. A chaotically nested Proto file can take a newcomer a week to understand the interface definition.

Standards are not constraints; they are meant to make code clearer and collaboration smoother. Spending half an hour establishing standards saves countless hours debugging bugs in the future.

Finally, let me leave you with one sentence: Code is written for people to read, and only incidentally for machines to execute.

Further reading ​

This article focuses on Protobuf naming conventions. For correct selection of data types, please refer to the second article in the series:

👉Protobuf Data Types Explained: A Practical Guide to enum, repeated, map, and oneof

Last updated on11/07/2026, 02:16 PM
@fishfinal | @fishfinals | [email protected]