Google protocol buffers for Clojure.
Clojure Java
Pull request Compare This branch is 58 commits behind ninjudd:develop.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Clojure-protobuf provides a clojure interface to Google's protocol buffers. Protocol buffers can be used to communicate with other languages over the network, and they are WAY faster to serialize and deserialize than standard Clojure objects.


Write a .proto file:

message Person {
  required int32  id    = 1;
  required string name  = 2;
  optional string email = 3;
  repeated string likes = 4;

If you put it in the proto directory of your project, you can compile it with leiningen:

lein protobuf compile example.proto

Now you can use the protocol buffer in clojure:

(use 'protobuf.core)
(import Example$Person)

(def Person (protodef Example$Person))

(def p (protobuf Person :id 4 :name "Bob" :email ""))
=> {:id 4, :name "Bob", :email ""}

(assoc p :name "Bill"))
=> {:id 4, :name "Bill", :email ""}

(assoc p :likes ["climbing" "running" "jumping"])
=> {:id 4, name "Bob", :email "", :likes ["climbing" "running" "jumping"]}

(def b (protobuf-dump p))
=> #<byte[] [B@7cbe41ec>

(protobuf-load Person b)
=> {:id 4, :name "Bob", :email ""}

A protocol buffer map is immutable just like other clojure objects. It is similar to a struct-map, except you cannot insert fields that aren't specified in the .proto file.


Clojure-protobuf supports extensions to protocol buffers which provide sets and maps using repeated fields. You can also provide metadata on protobuf fields using clojure syntax. To use these, you must import the extension file and include it when compiling. For example:

import "protobuf/core/extensions.proto";

message Photo {
  required int32  id     = 1;
  required string path   = 2;
  repeated Label  labels = 3 [(set)    = true];
  repeated Attr   attrs  = 4 [(map)    = true];
  repeated Tag    tags   = 5 [(map_by) = "person_id"];

  message Label {
    required string item   = 1;
    required bool   exists = 2;

  message Attr {
    required string key = 1;
    optional string val = 2;

  message Tag {
    required int32 person_id = 1;
    optional int32 x_coord   = 2 [(meta) = "{:max 100.0 :min -100.0}"];
    optional int32 y_coord   = 3;
    optional int32 width     = 4;
    optional int32 height    = 5;

Compile the file:

lein protobuf compile example.proto

Then you can access the maps in clojure:

(use 'protobuf)
(import Example$Photo)
(import Example$Photo$Tag)

(def Photo (protodef Example$Photo))
(def Tag (protodef Example$Photo$Tag))

(def p (protobuf Photo :id 7  :path "/photos/h2k3j4h9h23" :labels #{"hawaii" "family" "surfing"}
                       :attrs {"dimensions" "1632x1224", "alpha" "no", "color space" "RGB"}
                       :tags  {4 {:person_id 4, :x_coord 607, :y_coord 813, :width 25, :height 27}}))
=> {:id 7 :path "/photos/h2k3j4h9h23" :labels #{"hawaii" "family" "surfing"}...}

(def b (protobuf-dump p))
=> #<byte[] [B@7cbe41ec>

(protobuf-load Photo b)
=> {:id 7 :path "/photos/h2k3j4h9h23" :labels #{"hawaii" "family" "surfing"}...}

(:x-coord (protobuf-schema Tag))
=> {:max 100.0 :min -100.0}


You'll want to use this with the Leiningen build tool. You can get it by putting it in your :dependencies and/or :dev-dependencies. If you want to use the Leiningen plugin portion of clojure-protobuf, it has to be in your dev-dependencies.

:dev-dependencies [[protobuf "x.x.x"]]

Replace "x.x.x" with the actual latest version, which you can find on clojars

NOTE: clojure-protobuf requires at least version 1.7.0 of Leiningen. It will not work in earlier versions.


The build tool tasks provided with this library were originally for the cake build tool. In 2011, the authors of that tool decided that their time would be better spent working on a single, canonical build tool. Leiningen was already the standard for Clojure, so that's where we are now. As of version 0.6.0 (which has yet to see an final release, but is usable), all of the cake-specific functionality has been rewritten for Leiningen. Any version before that will not work with Leiningen.

Getting Help

If you have any questions or need help, you can find us on IRC in #flatland.