Skip to main content
The Ruby Protocol Buffers runtime (version 4.35-dev) provides a native C extension for MRI Ruby and a Java extension for JRuby. Both expose the same API.

Installation

1

Install the gem

Add to your Gemfile:
gem 'google-protobuf'
Or install directly:
gem install google-protobuf
Check RubyGems for the latest available version.
2

Install protoc

Download the prebuilt protoc binary for your platform from the releases page. The latest release supports the --ruby_out option.
3

Generate Ruby code

Run protoc with --ruby_out:
protoc --ruby_out=. addressbook.proto
This creates addressbook_pb.rb.

Working with messages

Require the generated file and the google/protobuf library:
require 'google/protobuf'
require './addressbook_pb'

# Create a person
person = Tutorial::Person.new(
  id: 1234,
  name: "Jane Doe",
  email: "[email protected]",
  phones: [
    Tutorial::Person::PhoneNumber.new(
      number: "+1-555-0100",
      type: :MOBILE
    )
  ]
)

# Set fields individually
person.id = 5678
person.name = "John Doe"

Encoding and decoding

encoded = Tutorial::Person.encode(person)

Full example: add_person.rb

This example reads an address book from disk, prompts for a new person, and writes it back:
#!/usr/bin/env ruby

require './addressbook_pb'
require 'pry'

def prompt_for_address()
  person = Tutorial::Person.new

  puts "Enter person ID number:"
  person.id = STDIN.gets.chomp.to_i
  puts "Enter name:"
  person.name = STDIN.gets.chomp

  puts "Enter email address (blank for none):"
  email = STDIN.gets.chomp

  if email != ""
    person.email = email
  end

  loop do
    puts "Enter a phone number (or leave blank to finish):"
    number = STDIN.gets.chomp

    if number == ""
      break
    end

    phone_number = Tutorial::Person::PhoneNumber.new(number: number)
    puts "Is this a mobile, home or work phone?"
    type = STDIN.gets.chomp

    case type
    when "mobile"
      phone_number.type = :MOBILE
    when "home"
      phone_number.type = :HOME
    when "work"
      phone_number.type = :WORK
    else
      puts "Unknown phone type; leaving as default value."
    end
    person.phones.push(phone_number)
  end
  person
end

if ARGV.length != 1
  puts "Usage: #{$0} ADDRESS_BOOK_FILE"
  exit(-1)
end

address_book = Tutorial::AddressBook.new()
if File.exist?(ARGV[0])
  f = File.open(ARGV[0], "rb")
  address_book = Tutorial::AddressBook.decode(f.read)
  f.close
else
  puts "#{$PROGRAM_NAME}: File not found. Creating new file."
end

person = prompt_for_address
address_book.people.push(person)

f = File.open(ARGV[0], "wb")
f.write(Tutorial::AddressBook.encode(address_book))
f.close

Basic usage pattern

Here is a minimal usage example from the Ruby README:
require 'google/protobuf'
require 'my_proto_types'  # generated from my_proto_types.proto

mymessage = MyTestMessage.new(field1: 42, field2: ["a", "b", "c"])
mymessage.field1 = 43
mymessage.field2.push("d")
mymessage.field3 = SubMessage.new(foo: 100)

encoded_data = MyTestMessage.encode(mymessage)
decoded = MyTestMessage.decode(encoded_data)
raise unless mymessage == decoded

puts "JSON:"
puts MyTestMessage.encode_json(mymessage)

FFI backend

An experimental FFI-based backend provides a unified C implementation across Ruby interpreters (MRI and JRuby). To opt in:
PROTOCOL_BUFFERS_RUBY_IMPLEMENTATION=FFI ruby your_script.rb
The FFI backend requires the ffi and ffi-compiler gems:
gem install ffi ffi-compiler
If ffi or ffi-compiler are not installed, or if the environment variable is not set to FFI, the traditional platform-native extension is used automatically.

Key API reference

Encode / Decode

MessageClass.encode(msg) returns a binary String. MessageClass.decode(bytes) returns a new message instance. These are class-level methods on every generated message class.

JSON

MessageClass.encode_json(msg) and MessageClass.decode_json(json_string) for canonical protobuf JSON.

Repeated fields

Repeated fields behave like Ruby arrays. Use standard array methods: push, each, map, length, etc.

Enums

Enum values are Ruby symbols (e.g., :MOBILE, :HOME). Assign and compare using symbols.

Build docs developers (and LLMs) love