# go-ceph: Go bindings that call the Ceph C libraries directly

> go-ceph is a cgo binding layer over Ceph's own C libraries, librados, librbd and libcephfs, so a Go program can talk to a Ceph cluster through the same calls the command line tools use instead of shelling out. The cost of that fidelity is that the build needs Ceph development headers, the binaries link dynamically rather than statically, and each supported Ceph release is selected with a build tag.

**ceph/go-ceph** — Go bindings for Ceph :octopus: :octopus: :octopus:

- Repository: https://github.com/ceph/go-ceph
- Stars: 694 · Forks: 297
- Language: Go
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/ceph-go-ceph

## Four sub-packages over three Ceph C libraries

go-ceph is described as a collection of API bindings that support the use of native Ceph APIs, which are C language functions, in Go, and it makes use of Go's cgo feature. That framing is the whole design in one sentence: there is no reimplementation of Ceph's logic in Go, there is a translation layer.

The sub-packages map onto the Ceph libraries. rados exports functionality from Ceph's librados, rbd from librbd, and cephfs from libcephfs. There is a fourth, rgw/admin, to interact with the radosgw admin ops API, which is a different thing entirely, an HTTP-style management interface to the object gateway rather than a C library.

The project states its aim as comprehensive support for the Ceph APIs over time, including both I/O related functions and management functions. And it names the audience: if your project makes use of Ceph command line tools and is written in Go, you may be able to switch away from shelling out to the CLI and to these native function calls.

That framing is exactly right for the situation the library exists for. Shelling out to rados or ceph and parsing stdout is a design that works until you need exit codes, or partial writes, or a call that the CLI does not expose.

The repository is MIT licensed, Go, and the most recent release is v0.42.1, published on 2026-10-14, and the repository is actively pushed to.

## Building needs the Ceph development headers, and the binaries link dynamically

The installation section is explicit that the code in go-ceph is purely a library module, typically imported into another Go project, and that the native RADOS, RBD and CephFS libraries and development headers are expected to be installed when building.

On debian based systems with apt those are:

```sh
libcephfs-dev librbd-dev librados-dev
```

On rpm based systems with dnf or yum they are:

```sh
libcephfs-devel librbd-devel librados-devel
```

And on MacOS the documentation points at a homebrew tap, brew tap mulbc/ceph-client followed by brew install ceph-client.

The consequence follows in the next paragraph and it is the one to plan around. Once compiled, code using go-ceph is expected to dynamically link to the Ceph libraries, those libraries must be available on the system where the Go binaries will run, and the use of cgo and the Ceph libraries does not allow for fully static binaries.

That rules out a class of deployment. If you are shipping a single binary into a scratch container, or building for a platform where the Ceph libraries cannot be installed, this is the wrong tool. A static binary requirement and Ceph are, at the library level, in direct conflict.

There is a quick way to check whether your system can build it at all, which is to run:

```sh
go get github.com/ceph/go-ceph
```

If that succeeds, cgo and the headers are in place.

## Build tags select the Ceph release, and the table shows the drift

go-ceph tries to support different Ceph versions, and the mechanism is build tags. Some functions are only available in recent versions and others may be deprecated, so to work with non-current versions of Ceph it is required to pass build-tags to the go command line, where a tag with the named Ceph release enables or disables certain features of the go-ceph packages, and prevents warnings or compile problems.

The example given is the tentacle release:

```sh
go build -tags tentacle ....
go test -tags tentacle ....
```

The supported version table is long enough to tell a story. The current v0.42.0 and v0.41.0 support squid, tentacle and umbrella, with quincy and reef listed as deprecated. v0.40.0 and v0.39.0 supported squid and tentacle with pacific also deprecated. Going back, v0.35.0 supported quincy, reef and squid with octopus deprecated, and the v0.19.0 row at the bottom of the table supports only pacific and quincy with nautilus and octopus deprecated.

So a project that started on v0.19.0 has been through many Ceph release names being added and removed, and the deprecation column is a record of that. What the tags affect is compile-time support, and the documentation is careful about a distinction that is easy to miss: what version of the Ceph cluster the client libraries support, and vice versa, is determined entirely by what version of the Ceph C libraries go-ceph is compiled with.

The tags are a compile-time switch, not a runtime negotiation. Get it wrong and you get compile errors or silent mismatches, not a helpful error at connect time.

## Developing against a vstart cluster without installing Ceph

For contributors, the documentation offers a path that avoids installing Ceph on the developer machine at all: run against a vstart.sh cluster instead.

That works by pointing cgo at the headers and libraries of a Ceph source tree:

```sh
export CGO_CPPFLAGS="-I/ceph/src/include"
export CGO_LDFLAGS="-L/ceph/build/lib"
go build
```

Three environment variables and a build. The headers come from the Ceph source, the libraries from a build directory, and cgo is told about both.

There is also a container route for development, using a Ceph CI image with the source mounted:

```bash
docker run --rm -it --net=host \
  --security-opt apparmor:unconfined \
  -v ${PWD}:/go/src/github.com/ceph/go-ceph:z \
  -v /home/nwatkins/src/ceph/build:/home/nwatkins/src/ceph/build:z \
  -e CEPH_CONF=/home/nwatkins/src/ceph/build/ceph.conf \
  ceph-golang
```

The volume mounts use the :z suffix for SELinux relabelling, and the CEPH_CONF environment variable points the client at a config file that lives in the mounted build directory.

The Makefile shows how the same idea is formalised for the test suite. CEPH_VERSION defaults to squid and drives BUILD_TAGS directly, with the container image tag derived from the release name, octopus to v15, pacific to v16, quincy to v17, reef to v18, squid to v19, tentacle to v20 and umbrella to v21. There are also pre- prefixed variants, pre-reef and pre-squid and so on, which consume pre-release Ceph images from quay.io/ceph/ceph-ci and add a second build tag such as ceph_pre_squid, which is how the project tests against a Ceph release before it ships. The integration tests run with make test-docker.

## A dependency list that reveals the RGW admin API is not cgo

The go.mod file is short, and one thing stands out immediately. The direct requirements are the AWS SDK for Go v2, with the config, credentials, s3 and sns services, the smithy-go core, gofrs/uuid, pierrec/xxHash, testify, and golang.org/x/sys.

An AWS SDK in a Ceph binding library looks strange until you remember that the rgw/admin sub-package talks to the RADOS Gateway admin API over the network, which is an S3-style and SNS-style interface rather than a C library. So part of go-ceph is a native cgo binding and part of it is an HTTP client, and the AWS SDK is there for the gateway half.

The other two dependencies are worth noting for what they say about the code. pierrec/xxHash is used for hashing, which matters for RGW object handling, and gofrs/uuid for identifier generation. The go directive is 1.26.0, so the toolchain floor is recent.

The repository layout follows the same split. There are rados/, rbd/, cephfs/ and rgw/ directories at the top level, plus common/ for shared code, internal/ for unexported helpers, testing/ for the container and cluster test setup, contrib/ and docs/ for supporting material, and a doc.go at the root. The docs directory also holds the API hints and how-tos document that the readme points to, which the readme describes as a way to quickly introduce how some API calls work together, and the older releases document recording what previous go-ceph versions supported.

## Where go-ceph is the wrong tool

There are situations where the cgo route is a liability rather than an advantage.

The static binary case is the clearest, and it is not a workaround but a hard constraint. If your deployment model is a scratch container, or a distroless image, or a binary you copy between machines with different library versions, go-ceph will not produce it. The same applies to cross-compilation for a target where the Ceph libraries do not exist, since cgo needs a toolchain for the target and the libraries themselves.

The version coupling is the second. Because support is decided at compile time by the tag and the Ceph headers you compiled against, an application that must talk to a cluster still on an older release needs the older go-ceph release and the older tag. The table in the readme is a record of how far that has moved, and the deprecation column means a version you deployed two years ago is now one upgrade away from losing support.

The third boundary is scope. go-ceph covers the C APIs. It does not give you a cluster, an object store abstraction, or a Kubernetes operator, and the rgw/admin package is the only part that is not a direct translation of a C library, so it behaves differently from the rest in terms of error handling and versioning.

For a service that shells out to a CLI today, switching to go-ceph is a clear win in correctness. For a static distribution, it is simply the wrong shape.

## Conclusion

Adopt go-ceph if you are writing a Go service that talks to a Ceph cluster and want native calls rather than parsing rados or ceph command output, because the bindings cover both the I/O and the management side of the Ceph APIs. Do not adopt it if you need a static binary, since the use of cgo and the Ceph libraries does not allow fully static binaries, and be careful if you are still on an older Ceph release, because the supported set moves with every go-ceph version. Before you start, check the version table for your go-ceph release against the Ceph version your cluster runs, and pass the matching build tag to go build and go test, because the tags decide which library features are compiled in and prevent compile errors against an older cluster.

## FAQ

### What does go-ceph provide over the Ceph command line tools?

It exports the native Ceph C APIs to Go through cgo, in the rados, rbd and cephfs sub-packages, plus an rgw/admin package for the radosgw admin ops API. The project states that a Go project using the Ceph command line tools may be able to switch from shelling out to the CLI to these native function calls.

### What do I need installed to build go-ceph?

The native RADOS, RBD and CephFS libraries and their development headers. On apt based systems that is libcephfs-dev, librbd-dev and librados-dev, on rpm based systems the -devel equivalents, and on MacOS the ceph-client formula from a homebrew tap. A quick check is to run go get github.com/ceph/go-ceph.

### How do I pick the right Ceph version for go-ceph?

Pass a build tag named for the Ceph release to go build and go test, for example go build -tags tentacle. The tags enable or disable library features and prevent compile problems, and the supported version table shows which Ceph releases each go-ceph version covers and which are deprecated.

### Can go-ceph produce a statically linked binary?

No. The documentation states that code using go-ceph is expected to dynamically link to the Ceph libraries, that those libraries must be available on the system where the Go binaries run, and that the use of cgo and the Ceph libraries does not allow for fully static binaries.

### How do I run the go-ceph integration tests?

In a docker container, with make test-docker. The Makefile drives the Ceph version through the CEPH_VERSION variable, which defaults to squid and also sets the build tags and the container image tag, with pre- prefixed variants for testing against pre-release Ceph images.

## Sources

- [ceph/go-ceph on GitHub](https://github.com/ceph/go-ceph)
- [Issues](https://github.com/ceph/go-ceph/issues)
- [License: MIT](https://github.com/ceph/go-ceph/blob/master/LICENSE)
- [README](https://github.com/ceph/go-ceph/blob/master/README.md)
- [Releases](https://github.com/ceph/go-ceph/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ceph-go-ceph
