Skip to main content
This guide walks you through the core Protocol Buffers workflow using the address book example from the protobuf repository. You will define a schema, compile it, and use the generated code to serialize and parse messages.
Before you begin, make sure you have installed protoc and the runtime library for your language. See the Installation guide for instructions.
1

Define a .proto file

Create a file named addressbook.proto. This schema defines two messages: Person (with nested PhoneNumber and PhoneType) and AddressBook.
addressbook.proto
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";

option java_multiple_files = true;
option java_package = "com.example.tutorial.protos";
option java_outer_classname = "AddressBookProtos";

message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;

  google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
A few things to note:
  • syntax = "proto3" selects the proto3 language version.
  • Field numbers (e.g., = 1, = 2) uniquely identify each field in the binary encoding. They must not change once your message type is in use.
  • The repeated keyword means the field can appear zero or more times (equivalent to a list).
  • import "google/protobuf/timestamp.proto" pulls in a well-known type bundled with protobuf.
2

Compile with protoc

Run protoc against your .proto file and specify the output directory for your target language.
protoc --python_out=. addressbook.proto
This generates addressbook_pb2.py in the current directory.To also generate a .pyi type stub for IDE support:
protoc --python_out=pyi_out:. addressbook.proto
Make sure the version of the language runtime you install matches (or is newer than) the version of protoc you compiled with.
3

Write data

Use the generated classes to build and serialize a message. The following examples read an address book from a file, add a person, and write it back out.
add_person.py
import addressbook_pb2
import sys

def PromptForAddress(person):
    person.id = int(input("Enter person ID number: "))
    person.name = input("Enter name: ")

    email = input("Enter email address (blank for none): ")
    if email != "":
        person.email = email

    while True:
        number = input("Enter a phone number (or leave blank to finish): ")
        if number == "":
            break

        phone_number = person.phones.add()
        phone_number.number = number

        type = input("Is this a mobile, home, or work phone? ")
        if type == "mobile":
            phone_number.type = addressbook_pb2.Person.MOBILE
        elif type == "home":
            phone_number.type = addressbook_pb2.Person.HOME
        elif type == "work":
            phone_number.type = addressbook_pb2.Person.WORK
        else:
            print("Unknown phone type; leaving as default value.")


address_book = addressbook_pb2.AddressBook()

# Read the existing address book.
try:
    with open(sys.argv[1], "rb") as f:
        address_book.ParseFromString(f.read())
except IOError:
    print(sys.argv[1] + ": File not found. Creating a new file.")

# Add an address.
PromptForAddress(address_book.people.add())

# Write the new address book back to disk.
with open(sys.argv[1], "wb") as f:
    f.write(address_book.SerializeToString())
4

Read data

Parse a serialized file and iterate over the messages it contains.
list_people.py
import addressbook_pb2
import sys

def ListPeople(address_book):
    for person in address_book.people:
        print("Person ID:", person.id)
        print("  Name:", person.name)
        if person.email != "":
            print("  E-mail address:", person.email)

        for phone_number in person.phones:
            if phone_number.type == addressbook_pb2.Person.MOBILE:
                print("  Mobile phone #:", end=" ")
            elif phone_number.type == addressbook_pb2.Person.HOME:
                print("  Home phone #:", end=" ")
            elif phone_number.type == addressbook_pb2.Person.WORK:
                print("  Work phone #:", end=" ")
            print(phone_number.number)


address_book = addressbook_pb2.AddressBook()

with open(sys.argv[1], "rb") as f:
    address_book.ParseFromString(f.read())

ListPeople(address_book)

Cross-language compatibility

Because all language runtimes share the same binary wire format, you can write data with one language and read it with another. For example, the address book examples in the protobuf repository all use the same addressbook.data file:
# Write using Python
python add_person.py addressbook.data

# Read using Java
java -cp .:protobuf-java-4.35.0.jar ListPeople addressbook.data

Next steps

  • Read the Installation guide to set up protoc and your language runtime.
  • Explore the full set of scalar types, nested messages, and field options in the proto3 language reference.

Build docs developers (and LLMs) love