45 How to Use `option` in Protobuf
One of the powerful features of Protocol Buffers (Protobuf) that many engineers often overlook is the use of option. Understanding and making the most of options in Protobuf can be tremendously helpful when designing API contracts that are more flexible and maintainable. In this article, I’ll cover thoroughly what option is, how to use it, examples of applying it at various levels, and even how to write your own custom options, complete with code examples, real-world case simulations, reference tables, and flow diagrams.
Getting to Know option in Protobuf
Before we dive into code examples, let’s briefly discuss what option actually is.
option in Protobuf is a metadata feature that can be attached to various entities such as files, messages, fields, enums, and services. Its purpose is to provide special instructions to the code generator (for example, protoc) or other tools that read the Protobuf schema.
Some of the options we frequently encounter include:
java_packagedeprecatedjson_namedefault
Placement and Scope of Options
Options can be placed at various levels. Let’s look at the following table for a summary:
| Scope | Example Option | Example Syntax in .proto |
|---|---|---|
| File | java_package | option java_package = "com.blog"; |
| Message | message_set_wire_format | option (xyz.my_opt) = true; |
| Field | deprecated, json_name | string username = 1 [deprecated=true]; |
| Enum/EnumVal | allow_alias | option allow_alias = true; |
| Service | - | option deprecated = true; |
| Custom | [custom options] | option (my_custom) = "value"; |
Examples of Built-in Options
Let’s get into real code. We’ll use a .proto file to demonstrate some of the most useful built-in options.
1syntax = "proto3";
2
3option java_package = "com.medium.protobuf";
4option go_package = "github.com/username/project/proto";
5
6message User {
7 string name = 1;
8 int32 age = 2 [deprecated = true];
9 string email = 3 [json_name = "userEmail"];
10}
11
12enum Status {
13 option allow_alias = true;
14 UNKNOWN = 0;
15 ACTIVE = 1;
16 ENABLED = 1;
17}Code explanation:
java_package&go_packageset the namespace of the code generator output in Java/Go.- The field option on
agemarks that field as deprecated, both in the documentation and in the runtime code. json_nameaffects the result of serialization to JSON.- On the enum, the option
allow_alias = trueallows two enum values (ACTIVE, ENABLED) to share the same number.
Automatically Generated Code Output
For example, on the deprecated age field, the generated output in Go (the comment in the struct) will look like this:
1// Deprecated: Do not use.
2Age int32 `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`This helps other teams know that this property should be avoided.
Custom Options: More Than Just Metadata
A truly powerful feature is the ability to define your own options, so that code generator plugins or linters can read unique instructions of your own making.
1. Define a Custom option
Custom options are defined via a proto extension of the google.protobuf standard options.
1// custom_options.proto
2syntax = "proto3";
3
4import "google/protobuf/descriptor.proto";
5
6extend google.protobuf.FieldOptions {
7 string sensitive = 50001;
8}2. Using It in a Protobuf Schema
1// user.proto
2syntax = "proto3";
3
4import "custom_options.proto";
5
6message User {
7 string password = 1 [(sensitive) = "Yes"];
8 string email = 2;
9}With this, a custom generator plugin can read whether a field contains a sensitive value (for example: a password), so that the logging layer can automatically mask it.
Simulating the Option Workflow (Mermaid)
Let’s imagine the workflow of how options are processed by the Protobuf toolset.
flowchart LR
subgraph Dev
A[Write .proto file] -->|Add option| B
end
B[Protoc Compiler] --> C{Baca option}
C -->|Standard option| D[Protoc generated code]
C -->|Custom option| E[Plugin / Linter]
E --> F[Custom Behavior]
Explanation:
- The engineer writes the .proto and fills in options at various scopes.
- The
protoccompiler reads the options. - For standard options, the official code generator applies the behavior.
- For custom options, a plugin or external tool can perform extra automation—for example masking, validation, generating additional documentation, and so on.
Case Study: Automatic Logging Masking
It often happens that sensitive fields such as passwords or tokens are not masked when logging requests in a backend service. With a custom option, we can automate this masking!
1. Tagging in the .proto
1message LoginRequest {
2 string username = 1;
3 string password = 2 [(sensitive) = "true"];
4}2. Implementation in Code Generation/Plugin
Your Go/Node.js plugin can read this metadata:
1if field.Options.Sensitive == "true" {
2 // When logging the request, mask this field as "*****"
3}The result:
1Received: {"username":"devuser","password":"*****"}Summary Table of Option Examples
| Option | Level | Purpose |
|---|---|---|
java_package | File | Namespace of generated code in Java |
go_package | File | Namespace of generated code in Go |
deprecated | Field | Marks a field/class as no longer recommended for use |
json_name | Field | Alternative name during JSON serialization |
allow_alias | Enum | Allow duplicate enum numbers |
**(sensitive) (custom) | Field | Custom metadata, e.g. masking instructions in logging |
When Should You Use Options?
- When the API spans multiple teams/programming languages
- When you want to enforce custom rules (custom linters, doc generators)
- When you need richer API contract documentation
- To automate behaviors such as default values, masking, deprecation
Conclusion
Using option in Protobuf is one of the highly beneficial techniques in managing data schemas & modern API communication. Standard options help with cross-language portability, while custom options open up opportunities for automation and enforcing semantic policy on enterprise APIs.
Don’t hesitate to experiment with custom options & Protobuf plugins. By understanding how options work, you can create APIs that are maintainable, future-proof, and trusted by the entire team ❤️