A while back, we announced that we had released the Buf Schema Registry (BSR), a centralized platform for managing Protobuf assets, into beta. In the announcement post, we briefly outlined a BSR feature called hosted plugins, which enables you to generate code using Protobuf plugins remotely, on the BSR, rather than on your local machine.
In this post, we'll dive a bit deeper into remote plugin execution and talk about why we built it, how it works, and how it can streamline your Protobuf workflows.
First, let's go over some of the basics of Protobuf plugins. A plugin is a program that a Protobuf compiler, like the buf
CLI or protoc, executes to convert Protobuf sources (.proto
files) into code stubs in your desired language, like Go, Java, C++, or Python. In order to use plugins, a compiler needs to support Protobuf's plugin protocol, whereby:
CodeGeneratorRequest
representing the .proto
files passed into the compiler, such as foo/bar.proto
, and sends that request to the plugin on stdin.CodeGeneratorResponse
to stdout.Protobuf's original protoc compiler provides some built-in plugins but you need to install any other plugins you need as executables in your environment. So if you needed to generate C++, Java, Python, Go, and Rust code from a Protobuf source, for example, three of those plugins are built into the compiler—C++, Java, and Python—but you'd need to install Go and Rust plugins on your own (protoc-gen-go
and protoc-gen-rust
are widely used options).
With the Go and Rust plugins installed, you could generate code stubs using a command like this:
protoc \
-I proto \
--cpp_out=gen/proto/cpp \
--java_out=gen/proto/java \
--python_out=gen/proto/python \
--go_out=gen/proto/go \
--rust_out=gen/proto/rust \
proto/api.proto
The buf
CLI streamlines this by replacing protoc in your workflows. So instead of that complex command invocation, you could use this buf.gen.yaml
configuration file...
version: v1
plugins:
- name: cpp
out: gen/proto/cpp
- name: java
out: gen/proto/java
- name: python
out: gen/proto/python
- name: go
out: gen/proto/go
- name: rust
out: gen/proto/rust
...and generate your code stubs with a single command:
$ buf generate <input>
Here, <input>
can be any valid Buf input, such as a directory, tarball, or Buf module. This is vastly more flexible than protoc, which only supports .proto
files as sources.
As you can see, the buf
CLI is a major improvement over protoc, which you no longer need to install or manage. But there is one remaining problem here: to run this example, you'd still need to install plugins locally and ensure that you're using the right plugin versions.
One half-solution is to either manage those executables yourself or rely on custom tooling, which frequently leads to those classic "works on my machine" reproducibility problems where you need to hunt down subtle differences in plugin versions used in different environments.
The difficulty of managing this complex web of compiler and plugin versions—just to make code stub generation work—has been a major barrier to Protobuf adoption. At Buf, we decided to fix this once and for all by removing the need for local plugins entirely.
With remote plugin execution, you can publish Protobuf plugins to the BSR and then execute those plugins on a trusted server—the BSR itself—rather than on your local machine.
Authoring a plugin involves two steps: building the plugin as a Docker image and pushing the image to plugins.buf.build
. Once your plugin has been pushed, you need to make one change to your buf.gen.yaml
configuration file to use it:
version: v1
plugins:
- remote: buf.build/my-buf-org/plugins/my-proto-plugin:v1.2.3
out: gen/proto/my-language
Note the usage of the remote
key rather than name
. With this configuration, the buf generate
command now makes a remote procedure call (RPC) to the BSR to execute the remote
plugin on your behalf. Here's an example generation command:
$ buf generate buf.build/acme/petapis
Here, the buf
CLI would generate code for the buf.build/acme/petapis
module using the local buf.gen.yaml
configuration. But instead of calling a local protoc-gen-my-proto-plugin
executable, all code generation would happen on the BSR, and the resulting files would be written to the gen/proto/my-language
directory.
This diagram illustrates that process:
The Buf team has developed processes to automatically sync and publish all of protoc's built-in plugins to the BSR under the buf.build/protocolbuffers
organization. This means that you can remove any and all plugin executables from your environment—local, CI/CD, whatever—and rely solely on remote plugins.
These protoc built-in plugins are hosted on the BSR:
buf.build/protocolbuffers/plugins/cpp
buf.build/protocolbuffers/plugins/csharp
buf.build/protocolbuffers/plugins/dart
buf.build/protocolbuffers/plugins/go
buf.build/protocolbuffers/plugins/java
buf.build/protocolbuffers/plugins/js
buf.build/protocolbuffers/plugins/kotlin
buf.build/protocolbuffers/plugins/objc
buf.build/protocolbuffers/plugins/php
buf.build/protocolbuffers/plugins/python
buf.build/protocolbuffers/plugins/ruby
We also host many popular gRPC plugins, including:
buf.build/grpc/plugins/cpp
buf.build/grpc/plugins/csharp
buf.build/grpc/plugins/go
buf.build/grpc/plugins/java
buf.build/grpc/plugins/kotlin
buf.build/grpc/plugins/node
buf.build/grpc/plugins/objc
buf.build/grpc/plugins/php
buf.build/grpc/plugins/python
buf.build/grpc/plugins/ruby
buf.build/grpc/plugins/web
Beyond that, some community members have made their own plugins publicly available on the BSR. We expect the number of community plugins to steadily expand over time.
You can replace protoc with the buf
CLI regardless of how you're using plugins. But using local plugins with buf
does have the drawback that you still need to install and manage those plugins yourself. Remote plugin execution goes one step further and enables you to eliminate not just protoc but even local plugin executables from your Protobuf workflows, making it easier than ever to introduce Protobuf into your environments.
Later in this series, we'll highlight some other BSR features, such as generated documentation for Protobuf and remote code generation.