Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
16 Jun 2025 · 6 min read ·Article 8 / 110
Go

8 Understanding the Basic Syntax of a Protobuf File

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

8. Understanding the Basic Syntax of a Protobuf File

Protobuf, or Protocol Buffers, is Google’s data serialization format that has since become the de facto standard for fast, efficient, and structured data communication. If you have already worked with REST APIs and JSON, you surely appreciate how easy it is to work with structured data. However, behind that convenience lies a trade-off in terms of size and parsing speed. This is exactly where Protobuf comes in, bringing efficiency to a much higher level.

In this article, we will dissect the basic syntax of a Protobuf file (.proto), dive into message structures, data types, and various other important features—plus include code examples, tables, and even a workflow diagram to reinforce your understanding.


Why Do You Need to Understand the .proto File?

A Protobuf file is the blueprint of our data: this is where we define the message structure, the data types, and how services call one another (the service definition, if you are using gRPC). A solid grasp of .proto file syntax speeds up debugging, migration, and the development of new features in a polyglot system.


1. Anatomy of a .proto File

Let’s start with the simple skeleton of a Protobuf file.

proto
1syntax = "proto3";
2
3package tutorial;
4
5message User {
6  int32 id = 1;
7  string name = 2;
8  bool is_active = 3;
9}

A brief explanation of each part:

PartDescription
syntaxThe Protobuf language version (proto2/proto3). Always using proto3 is recommended.
packageThe package/project name, useful for automatic namespacing in the generated code.
messageThe data structure (object) that will be serialized/deserialized
FieldThe definition of an attribute within a message: type, name, and tag number


2. Basic Data Types

Protobuf already provides many built-in types. Here is a summary table:

Protobuf TypeProgramming Language TypeDescription
doubledouble (float64)Double-precision floating-point number
floatfloat (float32)Single-precision floating-point number
int32, int64int, longSigned integers
uint32, uint64unsigned int, unsigned longUnsigned integers
sint32, sint64int, longSigned int, Zigzag encoded
fixed32, fixed64int/long (fixed bytes)Fixed value, precision matters
boolbooleanTrue/false value
stringstringUnicode UTF-8
bytesbyte[]Raw binary data

For every field, you must specify the type, the name, and the tag number. Example:

proto
1string email = 4;
The tag number is unique per field because it is used during serialize on the wire (range 1 - 2^29).


3. Understanding Messages and Nested Messages

A message (message) can be nested, meaning a message inside another message. For example:

proto
 1message Address {
 2  string street = 1;
 3  string city = 2;
 4}
 5
 6message User {
 7  int32 id = 1;
 8  string name = 2;
 9  Address address = 3;
10}

Protobuf supports composition, just like OOP in many languages; use it when you want type reusability.


4. Repeated Field (Array/List)

If a single entity can have many items, use repeated.

proto
1message User {
2  repeated string hobbies = 1;
3}
repeated means this field represents an array/list.

Encoding Simulation Suppose we send the following data:

json
1{
2  "hobbies": ["cycling", "reading", "gaming"]
3}
The serialized Protobuf binary will be efficient, far more economical than JSON.


5. Enum

Sometimes we want a field to only be filled with one of several available values. An enum is the solution.

proto
 1enum Status {
 2  UNKNOWN = 0;
 3  ACTIVE = 1;
 4  SUSPENDED = 2;
 5}
 6
 7message User {
 8  int32 id = 1;
 9  Status status = 2;
10}
Enum values always start from zero. This is important for the default value.


6. Map (Dictionary/Associative Array)

Since proto3, map<key, value> is allowed. Example:

proto
1message User {
2  map<string, string> metadata = 4;
3}
You can store dynamic data such as key-value pairs within a single field.


7. Service and RPC (optional)

In the modern world, a Protobuf file often contains an RPC contract (gRPC).

proto
1service UserService {
2  rpc GetUser (UserRequest) returns (UserResponse);
3}
The generated code will automatically provide a client and a server stub.


8. Simulation: Defining a Student Message

Let’s create a simple .proto file for a school application.

proto
 1syntax = "proto3";
 2package sekolah;
 3
 4enum Gender {
 5  UNKNOWN = 0;
 6  MALE = 1;
 7  FEMALE = 2;
 8}
 9
10message Address {
11  string jalan = 1;
12  string kota = 2;
13}
14
15message Siswa {
16  int32 id = 1;
17  string nama = 2;
18  Gender gender = 3;
19  repeated string hobi = 4;
20  Address alamat = 5;
21  map<string, int32> nilai = 6;
22}
Explanation:

  • Use an enum for Gender to keep things consistent
  • Address is reusable when Student and Teacher use the same type
  • The map for grades allows you to insert several subject scores

9. From Schema to Binary: The Protobuf Workflow

Let’s look at the workflow from defining a .proto file to using it in an application:

MERMAID
flowchart LR
    A[Buat File .proto] --> B["Generate Code (protoc)"]
    B --> C["Import ke Aplikasi (Go / Java / Python / dll)"]
    C --> D[Serialisasi Data]
    D --> E[Transmisikan Lewat Jaringan]
    E --> F[Deserialisasi di Sisi Penerima]
    F --> G[Data Terpakai di Aplikasi]

10. Best Practices

  • Field names should be snake_case: So they don’t clash when generated across various languages.
  • Use tag numbers consistently: Once you publish a tag, don’t change it—renaming is fine, as long as the tag number stays the same.
  • Set default values wisely: Keep in mind that proto3 does not support explicit defaults (the default is 0/empty); use an UNKNOWN enum value to work around this.
  • Enums always start from 0: For backward/forward compatibility.
  • Refactor gradually: If you must remove a field, give it a reserved prefix to stay safe.

Example of reserved:

proto
1message Siswa {
2  reserved 7, 8, 9;
3  reserved "telepon", "email";
4}


Conclusion

Understanding the basic syntax of a Protobuf file is an important investment for building data communication between systems that is robust, fast, and bandwidth-efficient. By mastering data types, messages, enums, repeated fields, and maps along with the best practices, engineers can design APIs, data schemas, and RPC contracts that are robust and maintainable.

If you’re curious, go ahead and create your own .proto file right away, generate code in your language of choice, and compare its performance with JSON or XML. I’m confident you’ll discover a brand-new thrill in cross-platform data collaboration!

Related Articles

💬 Comments