Skip to content

Go packages#

The BSR serves Go code for Protobuf messages and Connect/gRPC clients through the Go module proxy protocol. SDKs are generated on the fly when a go get request first asks for them, then cached for subsequent requests. Any go get works against the BSR with no extra tooling.

$ go get buf.build/gen/go/connectrpc/eliza/connectrpc/go

go: downloading buf.build/gen/go/connectrpc/eliza/connectrpc/go v1.11.0-20230913231627-233fca715f49.1
go: added buf.build/gen/go/connectrpc/eliza/connectrpc/go v1.11.0-20230913231627-233fca715f49.1

For an end-to-end walkthrough of finding and installing an SDK from the BSR, see the generated SDKs quickstart.

Go import paths#

A BSR-generated Go module path follows this format:

Go import path
BSR_INSTANCE/gen/go/ORGANIZATION/MODULE_NAME/PLUGIN_OWNER/PLUGIN_NAME

# Examples
buf.build/gen/go/connectrpc/eliza/connectrpc/go                       # public BSR
your-bsr-instance.buf.dev/gen/go/connectrpc/eliza/connectrpc/go       # Pro plan
your-bsr-instance.example.com/gen/go/connectrpc/eliza/connectrpc/go   # Enterprise plan

The placeholders:

  • BSR_INSTANCE is the BSR host (defaults to buf.build).
  • ORGANIZATION is the BSR organization that owns the module.
  • MODULE_NAME is the module name.
  • PLUGIN_OWNER is the owner of the plugin.
  • PLUGIN_NAME is the plugin name.

In the example above, the BSR generates code for the connectrpc/eliza module using the connectrpc/go plugin. The connectrpc/go plugin transitively depends on code generated by protocolbuffers/go, so the SDK pulls in the corresponding buf.build/gen/go/connectrpc/eliza/protocolbuffers/go SDK automatically.

To browse the package tree of a publicly available SDK, open it on pkg.go.dev (for example, pkg.go.dev/buf.build/gen/go/connectrpc/eliza/connectrpc/go).

For private SDKs, construct the import path by appending the Protobuf package to the module path:

Import path with Protobuf package
BSR_INSTANCE/gen/go/ORGANIZATION/MODULE_NAME/PLUGIN_OWNER/PLUGIN_NAME/PROTO_PACKAGE

# Example
buf.build/gen/go/connectrpc/eliza/connectrpc/go/connectrpc/eliza/v1

Plugins like Connect and gRPC place their generated code in subpackages alongside the message types (see Connect’s reasoning). Append the subpackage name to reach the importable handlers and clients:

Import path with plugin subpackage
BSR_INSTANCE/gen/go/ORGANIZATION/MODULE_NAME/PLUGIN_OWNER/PLUGIN_NAME/PROTO_PACKAGE/SUBPACKAGE

# Example
buf.build/gen/go/connectrpc/eliza/connectrpc/go/connectrpc/eliza/v1/elizav1connect

The duplication isn’t a typo: a well-named Protobuf package commonly shares elements with the module name.

Install an SDK#

go get accepts the BSR Go module path with any of the standard Go reference shorthands:

Latest commit on the default label
$ go get buf.build/gen/go/connectrpc/eliza/connectrpc/go@latest
Specific commit
$ go get buf.build/gen/go/connectrpc/eliza/connectrpc/go@COMMIT_ID
Specific label
$ go get buf.build/gen/go/connectrpc/eliza/connectrpc/go@LABEL
Explicit version string
$ go get buf.build/gen/go/connectrpc/eliza/connectrpc/go@v1.11.0-20230727062025-d8fbf2620c60.1

The BSR supports commits on labels, so referencing a non-default label fetches the matching unreleased Protobuf changes without disturbing the default label. Labels whose names contain / aren’t compatible with the Go SDK versioning scheme.

To pin a specific plugin version (rather than the latest plugin against a chosen module ref), use the buf registry sdk version CLI command.

Version string anatomy#

Version syntax
PLUGIN_VERSION-MODULE_TIMESTAMP-COMMIT_ID.PLUGIN_REVISION

# Example
v1.11.0-20230727062025-d8fbf2620c60.1
Part Example Source
Version core 1.11.0 Plugin version.
Pre-release: timestamp 20230727062025 Module commit timestamp (YYYYMMDDHHMMSS).
Pre-release: commit d8fbf2620c60 First 12 characters of the module commit ID.
Build metadata 1 Plugin revision.

Commits pushed to non-default labels carry 00000000000000 as the timestamp so they sort below released versions.

Proxy cache delay#

Warning

The public Go module proxy at https://proxy.golang.org caches BSR responses, which means a fresh buf push followed by go get ...@latest may not pick up the new commit for up to ~30 minutes (per the proxy.golang.org docs).

To bypass the public proxy and fetch directly from the BSR:

$ GOPRIVATE=buf.build/gen/go go get ...@latest

Private generated SDKs#

For SDKs generated from private BSR repositories, supply a personal API token (or a bot user token for CI) and tell the Go toolchain to skip the public proxy and checksum database for those imports.

Authenticate with buf registry login#

buf registry login writes credentials to ~/.netrc, and the Go toolchain reads .netrc when fetching private modules. For setup, see Authentication.

Configure GOPRIVATE#

Private modules can’t be fetched through the public proxy or verified through the public checksum database, so set GOPRIVATE:

$ export GOPRIVATE="buf.build/gen/go,${GOPRIVATE}"
$ go env -w GOPRIVATE="buf.build/gen/go,${GOPRIVATE}"

GOPRIVATE implicitly sets GONOPROXY and GONOSUMDB to the same value, so the toolchain uses the direct strategy and bypasses the public proxy and checksum database for the BSR host. For more, see Go’s private modules documentation.

Continuous integration#

For CI use of private generated SDKs, the canonical setup uses buf registry login plus GOPRIVATE. GitHub Actions example:

  1. Create a BSR token (or a bot user token for shared CI).
  2. Add a repository secret BUF_TOKEN set to the token.
  3. Add a repository secret BUF_USER set to the username the token belongs to.
  4. Set GOPRIVATE=buf.build/gen/go as a workflow environment variable, or as a repository secret.
  5. As a CI step, run:

    echo "${BUF_TOKEN}" | buf registry login --username "${BUF_USER}" --token-stdin
    

For other CI systems, the moving parts are the same: secret-store the token, export GOPRIVATE, log in with buf registry login before any go command runs.

Docker#

The Dockerfile below uses buf registry login and cleans up after itself so the credentials don’t end up in any image layer:

# syntax=docker/dockerfile:1.15

FROM golang:1.24-bookworm

ARG BUF_REGISTRY

ENV GOPRIVATE=${BUF_REGISTRY}/gen/go
COPY --from=bufbuild/buf:latest /usr/local/bin/buf /usr/local/bin/buf
WORKDIR /go/build
COPY go.mod go.sum /go/build/
RUN test -n "${BUF_REGISTRY}" || (echo "BUF_REGISTRY not set" && exit 1)
RUN --mount=type=secret,id=buftoken \
    buf registry login ${BUF_REGISTRY} --token-stdin < /run/secrets/buftoken \
 && go mod download || (buf registry logout; exit 1) \
 && buf registry logout

COPY . .
# Your build steps go here.
RUN go build

With BUF_TOKEN set in the build environment to the user’s (or bot user’s) API token, build the image with:

$ docker build . --secret id=buftoken,env=BUF_TOKEN --build-arg BUF_REGISTRY=<BSR_HOSTNAME>

Direct GOPROXY credentials (discouraged)#

Embedding credentials in GOPROXY is supported but discouraged: the URL ends up in shell history and process logs. Prefer buf registry login above.

export BUF_TOKEN="<your_token>"
export BUF_USER="<username_associated_with_token>"
# GOPROXY accepts a comma-separated list of proxies; embed credentials in the
# BSR proxy URL and keep your existing proxies as fallbacks.
export GOPROXY="https://${BUF_USER}:${BUF_TOKEN}@buf.build/gen/go,${GOPROXY}"
# Skip the public sum database for the BSR module path.
export GONOSUMDB="buf.build/gen/go,${GONOSUMDB}"

Direct GOPROXY credentials aren’t compatible with GOPRIVATE for the same host: only .netrc-based authentication via buf registry login works alongside GOPRIVATE.

Available plugins#

The full list of supported Go plugins lives on the BSR plugins page (filter for Go). For how those plugins are packaged, see the bufbuild/plugins repository; to request a new plugin, file an issue.

Troubleshooting#

Why does go get buf.build/gen/go/.../googleapis/googleapis/... return 404?#

The BSR intentionally doesn’t generate Go code for googleapis/googleapis. Every type in googleapis/googleapis carries a go_package option pointing at google.golang.org/genproto/googleapis; import the canonical package instead of regenerating the source.