We made improvements to remote code generation features of the BSR. This page has been replaced with a new BSR go module proxy section.
For existing users, please see the Migrating from alpha guide and if you run into issues contact us on Buf Public Slack.
The Buf Schema Registry (BSR) supports
remote code generation for Go. With this feature, you can
push Buf modules to the BSR and go get
Go code stubs generated from
those Protobuf definitions—without ever needing to generate code on your
own. Go source code generated by the BSR is hosted on the BSR's
Go module proxy.
With this feature, you no longer need to maintain Protobuf files or runtime dependencies like [protoc] plugins—in fact, JavaScript and TypeScript developers can avoid local code generation altogether for any Buf modules that have been pushed to the BSR.
This feature is especially useful for creating API clients for Go, as it provides consumers of your API with generated Go SDKs on demand. With remote generation, you no longer need to generate Go code from Protobuf locally, and thus no longer need for consumers to pull in Protobuf files or perform any generation whatsoever.
BSR Go module proxy
The BSR Go module proxy implements the GOPROXY protocol for Buf
modules by generating assets on the fly—Go code stubs aren't
generated until you request them using go get
.
The key to consuming from the BSR Go module proxy is choosing the right Go module path. The import path for generated Go code has this format:
So if you wanted to, for example, generate the acme/paymentapis
Protobuf module using the grpc/go
template, you could install the
generated code like this:
$ go get go.buf.build/grpc/go/acme/paymentapis
You can use any template that generates Go, which can simplify Protobuf workflows down to two steps:
buf push
your module to the BSRgo get
your generated Go module
Try it out!
In this example, we'll use the Go gRPC client for the Eliza demo
service. Since this is a gRPC/Protobuf API we get a generated client SDK with
minimal effort. The grpc/go
template is used to generate the
bufbuild/eliza
module.
See the above for a refresher on Go module import paths.
package main
import (
"context"
"crypto/tls"
"log"
// Import the Eliza API definitions and generate using the template grpc/go.
elizav1 "go.buf.build/grpc/go/bufbuild/eliza/buf/connect/demo/eliza/v1"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
func main() {
cc, err := grpc.Dial(
"demo.connect.build:443",
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
)
if err != nil {
log.Fatalf("Failed to dial GCS API: %v", err)
}
client := elizav1.NewElizaServiceClient(cc)
resp, err := client.Say(context.Background(), &elizav1.SayRequest{
Sentence: "Hello remote generation",
})
if err != nil {
log.Fatalf("Failed to get bucket: %v", err)
}
log.Println(resp)
}
If you're using Go modules you'll observe a version such as v1.4.6
in the
go.mod
file. To better understand versioning, see the
synthetic versions documentation.
require (
go.buf.build/grpc/go/bufbuild/eliza v1.4.6
)
Generate private modules
To generate Go code from private modules you'll need to make sure the Go tooling is correctly configured.
-
Log into the BSR:
The
go
tool uses.netrc
credentials if available and you can usebuf registry login
to add this to your.netrc
file. You can obtain an API token (password) from the Settings page.$ buf registry login
~/.netrcmachine buf.build login <USERNAME> password <TOKEN> machine go.buf.build login <USERNAME> password <TOKEN>
-
Go Environment Configuration
The
GOPRIVATE
environment variable controls which modules thego
command considers to be private and thus shouldn't use the proxy or checksum database. This is important since you don't want to send private information to the default Go module proxy at https://proxy.golang.org.Set this environment variable:
$ export GOPRIVATE=go.buf.build
If you already have
GONOSUMDB
configured, you also need to addgo.buf.build
to it:$ export GONOSUMDB=$GONOSUMDB,go.buf.build
This isn't necessary if you do not already have
GONOSUMDB
configured, asGOPRIVATE
automatically sets it in this case.For more information, see the official private modules documentation.