Skip to content

Protocol Buffers — The Foundation of gRPC Serialization

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Protocol Buffers. We cover key concepts, practical examples, and best practices to help you master this topic.

Protocol Buffers (protobuf) is Google's language-neutral, platform-neutral extensible mechanism for serializing structured data, used as the foundation for gRPC communication.

What You'll Learn

You will learn how Protocol Buffers work, message structure, field numbering, Serialization format, and how they compare to JSON and XML.

Why Protocol Buffers Matter

JSON is human-readable but verbose and slow to parse. Protocol Buffers are binary, compact, and extremely fast. gRPC uses protobuf for message serialization, achieving 3-10x better performance than JSON-based APIs. DodaTech's Durga Antivirus Pro processes millions of threat intelligence updates daily — switching from JSON to protobuf reduced message size by 70% and Parsing time by 85%.

flowchart LR
    A["Proto Definition\n(threat.proto)"] -->|"protoc compiler"| B["Generated Code\n(Python, Go, JS)"]
    A --> C["Protobuf Binary\n(wire format)"]
    C --> D["Smaller (70% less)"]
    C --> E["Faster (10x)"]
    C --> F["Typed (validation)"]
    style A fill:#dbeafe,stroke:#2563eb
    style B fill:#fef3c7,stroke:#d97706
    style C fill:#bbf7d0,stroke:#16a34a
â„šī¸ Info

Prerequisites: Basic understanding of serialization and data formats.

Defining a Message

syntax = "proto3";

package dodatech.threat.v1;

message Threat {
  string id = 1;
  string name = 2;
  string severity = 3;
  string detected_at = 4;
  string device_id = 5;
  int32 score = 6;
  repeated string tags = 7;
  map<string, string> metadata = 8;
}

Serialization Example

import threat_pb2

threat = threat_pb2.Threat()
threat.id = "thr-001"
threat.name = "Emotet"
threat.severity = "CRITICAL"
threat.score = 95
threat.tags.extend(["ransomware", "emotet"])
threat.metadata["source"] = "honeypot-01"

# Serialize to bytes
data = threat.SerializeToString()
print(f"Protobuf size: {len(data)} bytes")
# Protobuf size: 52 bytes

# Compare: JSON would be ~180 bytes for the same data
# JSON: {"id":"thr-001","name":"Emotet","severity":"CRITICAL","score":95,...}

# Deserialize
threat2 = threat_pb2.Threat()
threat2.ParseFromString(data)
print(threat2.name)  # "Emotet"

Field Types

Protobuf Type Go Type Python Type Java Type Notes
double float64 float double
float float32 float float
int32 int32 int int
int64 int64 int long
uint32 uint32 int int unsigned
bool bool bool boolean
string string str (unicode) String UTF-8
bytes []byte bytes ByteString
repeated []T list List Array

Common Mistakes

1. Changing Field Numbers

Field numbers are the identity of fields in the binary format. Never reuse or change field numbers — only add new ones.

2. Using required in proto3

proto3 removed the required keyword. All fields are optional by default.

3. Not Using Oneof for Mutually Exclusive Fields

Use oneof when a message can contain one of several fields. It saves space and enforces mutual exclusion.

4. Making Messages Too Large

A single protobuf message should not exceed 4MB. For larger data, use streaming or split into multiple messages.

5. Ignoring Field Number Ranges

Field numbers 1-15 use 1 byte, 16-2047 use 2 bytes. Reserve numbers 1-15 for frequently used fields.

Practice Questions

  1. What is the advantage of protobuf over JSON?
  2. Why are field numbers important?
  3. What does the repeated keyword do?
  4. What is oneof in protobuf?
  5. How does protobuf handle backward compatibility?

Answers:

  1. Protobuf is binary (3-10x smaller), strongly typed (safety), and faster to serialize/deserialize than JSON.
  2. Field numbers identify fields in the binary encoding. They must be unique per message and never changed once used.
  3. repeated defines an array/list of a type. It can contain zero or more elements.
  4. oneof defines a set of fields where at most one can be set at a time. The compiler generates special accessors.
  5. Protobuf uses field numbers, not field names, for encoding. You can add new fields without breaking old clients — they ignore unknown fields.

Challenge: Design Protocol Buffer messages for DodaTech's complete threat intelligence system. Include messages for Threat, Device, User, Scan, and Alert with proper field numbering, types, and package structure.

FAQ

Is protobuf human-readable?

Not natively — it's a binary format. Use protoc --decode or tools like protobuf-inspector for debugging. grpcurl can decode gRPC responses to JSON.

How do I version protobuf schemas?

Use packages (package dodatech.threat.v1) and never remove fields. Add new fields with new numbers. Old clients ignore unknown fields.

Can I use protobuf without gRPC?

Yes — protobuf is independent of gRPC. Use it for data storage, configuration files, or any serialization need.

Mini Project

Create .proto files for DodaTech's device management. Include messages for Device, DeviceList, CreateDeviceRequest, and UpdateDeviceRequest. Generate Python and JavaScript code. Write a script that serializes a device and deserializes it.

What's Next

Topic Description
Proto Syntax proto3 language features
gRPC Introduction Review gRPC fundamentals
âŦ… gRPC Introduction
➡ Proto Syntax

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro