Skip to main content
The Go Protocol Buffers module provides generated structs and a runtime API for marshaling, unmarshaling, cloning, and comparing messages.

Installation

1

Add the Go protobuf module

go get google.golang.org/protobuf
2

Install the protoc-gen-go plugin

The protoc-gen-go plugin generates Go code from .proto files. Install it and make sure $GOPATH/bin is on your $PATH:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
3

Install protoc

Download the prebuilt protoc binary for your platform from the releases page.

Generating code

Use protoc with --go_out and --go_opt to generate Go source files. The go_package option in your .proto file sets the import path:
// addressbook.proto
syntax = "proto3";
package tutorial;

option go_package = "github.com/protocolbuffers/protobuf/examples/go/tutorialpb";
protoc --go_out=. --go_opt=paths=source_relative addressbook.proto
This creates addressbook.pb.go in the current directory.

Working with messages

Generated structs have exported fields for each proto field. Use the proto package for marshaling:
package main

import (
    "log"

    "google.golang.org/protobuf/proto"
    tutorialpb "github.com/protocolbuffers/protobuf/examples/go/tutorialpb"
)

func main() {
    // Create a message
    person := &tutorialpb.Person{
        Name:  "Jane Doe",
        Id:    1234,
        Email: "[email protected]",
        Phones: []*tutorialpb.Person_PhoneNumber{
            {
                Number: "+1-555-0100",
                Type:   tutorialpb.Person_MOBILE,
            },
        },
    }

    // Marshal to bytes
    data, err := proto.Marshal(person)
    if err != nil {
        log.Fatal("marshaling error: ", err)
    }

    // Unmarshal from bytes
    newPerson := &tutorialpb.Person{}
    if err := proto.Unmarshal(data, newPerson); err != nil {
        log.Fatal("unmarshaling error: ", err)
    }

    log.Printf("Name: %s", newPerson.GetName())
}

Marshaling and unmarshaling

import "google.golang.org/protobuf/proto"

data, err := proto.Marshal(msg)
if err != nil {
    // handle error
}

Utility functions

Clone

Create a deep copy of a message:
import "google.golang.org/protobuf/proto"

copy := proto.Clone(person).(*tutorialpb.Person)

Equal

Compare two messages for equality (field-by-field, ignoring unknown fields by default):
if proto.Equal(person1, person2) {
    fmt.Println("messages are equal")
}

Merge

Merge one message into another (non-zero fields in src overwrite fields in dst):
proto.Merge(dst, src)

JSON support

Use protojson for JSON marshaling that conforms to the canonical protobuf JSON mapping:
import "google.golang.org/protobuf/encoding/protojson"

// Marshal to JSON
jsonBytes, err := protojson.Marshal(person)

// Unmarshal from JSON
newPerson := &tutorialpb.Person{}
err = protojson.Unmarshal(jsonBytes, newPerson)

Key API reference

proto.Marshal / proto.Unmarshal

Core binary serialization. proto.Marshal returns []byte. proto.Unmarshal populates an existing message pointer.

proto.Clone

Deep-copies a message. The return type is proto.Message; cast to the concrete type as needed.

proto.Equal

Reports whether two messages are equal. Extension fields and unknown fields are included in the comparison.

protojson

google.golang.org/protobuf/encoding/protojson — JSON encoding with canonical field name mapping, EmitUnpopulated, and UseEnumNumbers options.
Use accessor methods like GetName() rather than direct struct field access when writing library code. Accessor methods are nil-safe and return the default value for unset fields.

Build docs developers (and LLMs) love