Gophercloud: the Go SDK where a ProviderClient buys you a ServiceClient
Gophercloud: an OpenStack SDK for Go
At a glance
- What is it?
- Gophercloud is an OpenStack SDK for Go, organised around two layered client abstractions, a ProviderClient that holds your token and a ServiceClient per OpenStack module. It has a two-layer client model, a clouds.yaml based config path, a per-service acceptance test suite, and a v3 development branch alongside the stable v2 line.
- Who is it for?
- Gophercloud fits a Go team writing against an OpenStack cloud who wants typed request and response structs per service rather than hand-built HTTP calls, and who wants context cancellation and tracing threaded through every request. It is the wrong choice for a Python or Terraform shop, and the wrong choice for a team that has not yet decided which OpenStack services it will use.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two client types, and the reason there are two
Gophercloud is a Go SDK for OpenStack, and the thing to understand first is its client model, because everything else follows from it.
Gophercloud authentication is organized into two layered abstractions. `ProviderClient` holds the authentication token and can be used to build a `ServiceClient`. `ServiceClient` specializes against one specific OpenStack module and can directly be used to make API calls. A provider client is a top-level client that all of your OpenStack service clients derive from, and it contains all of the authentication details that allow your Go code to access the API, such as the base URL and token ID.
The relationship is one to many: a single provider client can be used to build as many service clients as needed. So the token acquisition happens once, and every service you use, compute, block storage, object storage, networking, draws from the same authenticated provider.
This split is not an implementation detail, it is the mental model. Authentication is a property of the deployment, endpoint resolution is a property of the service plus region, and the API calls are a property of the resource. Three different lifetimes, three different types, and the SDK makes you name them separately.
The module path is `github.com/gophercloud/gophercloud/v2`, and the Go version floor declared in go.mod is 1.25.0. The package has two direct dependencies, `go.yaml.in/yaml/v3` and `golang.org/x/crypto`, with everything else marked indirect, including test tooling like `gotest.tools/gotestsum`, which is declared as a Go tool rather than a plain dependency.
Credentials belong in clouds.yaml, and Horizon hands it to you
Because you are hitting an API, you need OpenStack credentials, and the SDK offers three places to put them: a `clouds.yaml` file, environment variables, or your local Go files. The first is recommended, and the reason given is worth repeating in a review, because it is a habit that prevents a real class of incident. Storing credentials in `clouds.yaml` decouples credential information from source code, which allows you to push the source to your version control system without any security risk.
You need a valid Keystone identity URL and credentials, and the credential form is not limited to a username and password. It can be a username and password combo, a set of Application Credentials, a pre-generated token, or any other supported authentication mechanism. Application Credentials in particular are the OpenStack mechanism designed for exactly this use case, giving a service its own scoped identity rather than reusing a human's password.
For users with the OpenStack dashboard installed, there is a shortcut that removes most of the friction. If you visit the `project/api_access` path in Horizon and click the "Download OpenStack RC File" button at the top right hand corner, you can download either a `clouds.yaml` file or an `openrc` bash file that exports all of your access details to environment variables. To use the `clouds.yaml` file, place it at `~/.config/openstack/clouds.yaml`. To use the `openrc` file, run `source openrc` and you will be prompted for your password.
That last detail is worth a sentence on its own. The `openrc` file does not contain your password, it exports the environment variables and asks for the password when you source it, so the credential never lands in a file at all. The `clouds.yaml` path is the one to prefer for automation, the `openrc` path for a shell session.
Three ways to build a provider, and context everywhere
The SDK shows the same task three times, once per credential source, and comparing them is the fastest way to understand the API.
With `clouds.yaml`, the code calls `clouds.Parse()`, which fetches coordinates from a `clouds.yaml` in the current directory or in the well-known config directories, which are different for each operating system. It returns four values, the auth options, the endpoint options, a TLS config, and an error. Then `config.NewProviderClient(ctx, authOptions, config.WithTLSConfig(tlsConfig))` calls Keystone to get an authentication token, and `openstack.NewComputeV2(ctx, providerClient, endpointOptions)` builds the compute client.
With environment variables from `openrc`, the code calls `openstack.AuthOptionsFromEnv()` and then `openstack.AuthenticatedClient(ctx, opts)`. The compute client is then built with `gophercloud.EndpointOpts{Region: os.Getenv("OS_REGION_NAME")}`.
Manually, the code passes `gophercloud.AuthOptions` with an `IdentityEndpoint` of the form `https://openstack.example.com:5000/v3`, a `Username`, and a `Password`, and builds the compute client with `gophercloud.EndpointOpts{Region: "RegionName"}`.
What is common to all three is the `context.Context` as the first argument, and the project is explicit about why: all functions hitting the OpenStack API accept a `context.Context` to enable tracing and cancellation, and the constructor accepts a context for endpoint resolution, cancellation, and tracing. Every network call in this SDK is cancellable and traceable, which is a design decision that pays off in a server that has request deadlines and in an operator trying to follow a slow call.
The `openstack/config` package with the `clouds` subpackage is where the first style lives, which is a hint about how the config surface is organised relative to the older, simpler `openstack` package that holds `AuthOptionsFromEnv` and `AuthenticatedClient`.
Making a call means typed options and an Extract step
The resource layer follows a pattern that is consistent across the SDK, and the compute example shows it.
import "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers"
func main() {
// [...]
server, err := servers.Create(context.TODO(), computeClient, servers.CreateOpts{
Name: "My new server!",
FlavorRef: "flavor_id",
ImageRef: "image_id",
}, nil).Extract()
// [...]The `Create` method takes the context, the service client, an options struct, and a trailing nil, and returns something you call `Extract` on to get the concrete type. The options struct is where the API request body lives, with `Name`, `FlavorRef`, and `ImageRef` for a server, where the flavor ID is the hardware specification and the image ID is the operating system. The result is a `servers.Server`.
The `Extract` step is the part that makes the SDK worth using. The call returns a result wrapper that knows how to pull the payload out of the HTTP envelope, and `Extract` turns it into a typed struct. Every service in the SDK follows the same shape, so a caller who learns it once has it everywhere, and the compiler catches a field rename that would otherwise be a runtime surprise.
The passing of `context.TODO()` in the example is a hint rather than a recommendation, since the surrounding examples use a real `ctx` from `context.Background()`. The SDK accepts a context everywhere so that a request deadline can be passed down, and using `TODO` in your own code throws that away.
The support table is versioned, and some services are missing from 2.x
The supported services table is the most decision-relevant thing in the project, and it has a column most support tables do not have. Each service is listed with its OpenStack project name, the module path, and a separate tick for 1.x and 2.x.
Baremetal, which is Ironic, is supported in both, and so is Baremetal Introspection, which is Ironic Inspector. Block Storage, which is Cinder, is supported in both. Compute, which is Nova, is supported in both. Container, which is Zun, is supported in both.
Clustering, which is Senlin, is the row to look at carefully. It is marked as supported in 1.x and marked with a cross in 2.x. That is a real gap, and it is the kind of detail that a support list without version columns would hide. If your deployment uses Senlin clustering, the 2.x line does not cover it.
The pattern to read it with is that a tick means the service module exists in that major version, and a cross means it does not.
There is also a versioning story that explains the table. The default branch is `main` and it contains the current development version of Gophercloud, which is `v3`. Backward-compatible changes are backported to the current stable branch, `v2`, and the legacy stable version is in the `v1` branch. So the module path in your go.mod tells you which generation you are on, and the table tells you which services that generation covers.
For a team choosing an SDK, this is the part to read first. Service coverage per major version is the constraint that determines whether the library works for your cloud at all.
Acceptance tests per service, and a containerised linter
The Makefile is where the project's engineering practice shows, and two things in it are worth describing.
The first is the acceptance suite. There is an `acceptance` target that chains named acceptance targets, one per service area, including acceptance-basic, acceptance-baremetal, acceptance-blockstorage, acceptance-compute, acceptance-container, acceptance-containerinfra, acceptance-db, acceptance-dns, acceptance-identity, acceptance-image, acceptance-keymanager, acceptance-loadbalancer, acceptance-messaging, acceptance-metric, acceptance-networking, acceptance-objectstorage, acceptance-orchestration, acceptance-placement, acceptance-reservation, acceptance-sharedfilesystems, and acceptance-workflow.
Each runs the test binary with a timeout of 60 minutes and the build tags `fixtures acceptance`. The build tags are how the acceptance tests are separated from the unit tests, and the per-service split means you can run acceptance tests for the one service you are changing rather than for the whole cloud.
The second is the lint target, which runs golangci-lint inside a container. The runner is chosen at make time: if `podman` is available it is used, otherwise `docker`. The version is pinned to v2.12.1, the working directory is mounted at /app, the cache directory is mounted separately, and the environment sets GOFLAGS to the acceptance build tag, so the linter sees the acceptance-tagged code as well. There is a comment block explaining the failure messages you may see, including the SELinux `chcon` commands to run if the container cannot write its cache.
The unit and coverage targets both use `-shuffle on` on the test run, which is the detail that matters most for an SDK with a lot of shared state. Shuffling test order is how you find tests that depend on each other, and the coverage target adds `-covermode count`, a coverage profile, and `-coverpkg=./...` so that coverage counts the packages the tests exercise rather than only the packages that contain them. The `format` target is `gofmt -w -s` over the working directory.
The tree also has a `.golangci.yaml` for the linter configuration, a `CHANGELOG.md`, a `RELEASE.md`, and a `script/` directory.
Editorial conclusion
Gophercloud fits a Go team writing against an OpenStack cloud who wants typed request and response structs per service rather than hand-built HTTP calls, and who wants context cancellation and tracing threaded through every request. It is the wrong choice for a Python or Terraform shop, and the wrong choice for a team that has not yet decided which OpenStack services it will use. Check three things before you commit: that your Go version is 1.25.0 or newer, which is the module's declared floor, which branch you target, since main carries the v3 development version while backward-compatible changes are backported to the stable v2 branch, and that the services in the support table include the ones you need, because the table marks coverage per major version and some services are marked as not present in 2.x.
Frequently asked questions
What is Gophercloud and how do I install it?
Gophercloud is a Go SDK for OpenStack. You import `github.com/gophercloud/gophercloud/v2` in your code and then run `go mod tidy` to update your go.mod. The module declares a Go version floor of 1.25.0.
What is the difference between ProviderClient and ServiceClient?
Gophercloud authentication is organized into two layered abstractions. The ProviderClient holds the authentication token and the details needed to reach the API, such as the base URL and token ID, and it can build ServiceClients. A ServiceClient specializes against one specific OpenStack module and is used directly to make API calls, and one provider client can build as many service clients as needed.
Where should I put my OpenStack credentials?
In a `clouds.yaml` file, which is the recommended method because it decouples credential information from source code so the source can be pushed to version control without risk. You can download a `clouds.yaml` or an `openrc` file from the `project/api_access` path in the OpenStack dashboard, and the `clouds.yaml` goes at `~/.config/openstack/clouds.yaml`.
Which OpenStack services does Gophercloud support?
The support table lists services with their OpenStack project names and modules, and marks support per major version separately. Baremetal, Block Storage, Compute, and Container are supported in both 1.x and 2.x, while Clustering, which is Senlin, is marked as supported in 1.x but not in 2.x, so check the table for the specific service you need.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gophercloud-gophercloud)Was this useful?