go-discover: finding service addresses across fifteen cloud providers
Discover nodes in cloud environments
At a glance
- What is it?
- HashiCorp's go-discover takes a string of key=value pairs, picks a provider out of it, and returns the IP addresses of the nodes that match a tag, in AWS, Azure, GCE, DigitalOcean, Aliyun, OpenStack, vSphere and more. The README also says the project is feature complete and maintained on an as-need basis, with go-netaddrs being the actively maintained alternative.
- Who is it for?
- Adopt go-discover when you already run Consul or Vault and need their service discovery to find nodes in a specific cloud, since the tag conventions and the provider set are exactly what those products expect. Do not adopt it as a general purpose address finder, because the README states it is feature complete, maintained on an as-need basis, and that go-netaddrs is the actively maintained solution for discovering IP addresses without tying to specific infrastructure.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 11 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A feature complete library with a successor already named
go-discover is a Go library and command line tool to discover IP addresses of nodes in cloud environments based on meta information like tags provided by the environment.
The first thing to know is stated in a note at the top of the README: go-discover is considered feature complete and is currently maintained on an as-need basis for use with Vault and Consul. Another solution, go-netaddrs, is being actively maintained, and it provides a more flexible way of discovering IP addresses without having to tie it to specific infrastructure.
That sentence is the most important line in the project for an evaluator, and it is worth reading twice. This is a library that reached its intended scope, is kept alive for the products that depend on it, and has a named successor for new work. HashiCorp built the thing they needed, and the need was Consul and Vault discovering the nodes of a service across whatever cloud the user happened to run in.
The release history supports that reading rather than contradicting it. Version 1.5.0 was tagged on 2026-09-18, 1.4.0 on 2026-07-29 and 1.3.0 on 2026-06-10, so there is recent work, and the repository is not archived, with the last push on 2026-10-12. The licence is MPL-2.0, the primary language is Go, and the default branch is master.
The design that follows from that brief is narrow on purpose. One input, a configuration string. One output, a list of addresses.
The configuration string, and how quoting works
The configuration for the providers is provided as a list of key=val key=val tuples, and the provider is determined through the `provider` key. Duplicate keys are reported as an error, which is a small but useful detail, since a config string with a repeated key is almost always a mistake rather than an intent.
The quoting rules are spelled out because they have to be. If either the key or the value contains a space, a backslash or double quotes, then it needs to be quoted with double quotes. Within a quoted string you can use the backslash to escape double quotes or the backslash itself, with the example given as `key=val "some key"="some value"`.
That is a shell-like format without a shell, which is the point. The same string has to work whether it comes from a Consul agent config file, a Vault configuration, a command line argument, or an environment variable, and it has to survive all four without a parser.
The provider list in the README shows what the values look like in practice. A configuration that needs no credentials at all is the mDNS provider, which takes a service and a domain:
provider=mdns service=consul domain=localDNS SRV records work the same way, with a service, a protocol and a domain:
provider=srv service=consul proto=tcp domain=consulAnd the Kubernetes provider takes a label selector in the same key=value form:
provider=k8s label_selector="app = consul-server"The Kubernetes example is the one that needs the quoting rule, since the selector value contains spaces.
Sixteen registered providers, one that is not
The provider implementations live in the go-discover/provider sub packages, and additional providers can be added through the Register function.
The registered list covers Aliyun, Amazon AWS, DigitalOcean, Google Cloud, Linode, mDNS, Microsoft Azure, OpenStack, Scaleway, SoftLayer, SRV, TencentCloud, Triton, vSphere and Packet. That is fifteen registered providers, spanning the major clouds plus the older or more specialised ones that a HashiCorp user base would have run on: Triton, SoftLayer, vSphere and Aliyun are all providers that have been important to particular segments of that audience.
One provider is deliberately different. The Kubernetes provider is implemented in the provider subdirectory but is not automatically registered. If you want it, you register it manually. The reason is structural rather than accidental: registering Kubernetes pulls a client-go dependency into every build of the library, and the maintainers chose not to impose that on users who will never touch a cluster.
The rest of the tree reflects the same discipline. The top level holds config.go, discover.go, go.mod, go.sum, a Makefile, a CHANGELOG.md, CODEOWNERS, CONTRIBUTING.md, a .copywrite.hcl file for licence headers, and directories for cmd/, provider/ and test/.
One dependency in the module list is telling. The GCE provider is not a plain subpackage here; go.mod requires github.com/hashicorp/go-discover/provider/gce at a pinned pseudo-version, which means the Google Cloud implementation lives in its own repository and is pulled in as a module. That is a good sign for the project's structure, since it keeps the cloud specific dependencies outside the core.
Acceptance tests against real cloud resources
HashiCorp maintains acceptance tests that regularly allocate and run tests with real resources to verify the behavior of several of these providers.
The providers covered are Amazon AWS, Microsoft Azure, Google Cloud, DigitalOcean, Triton, Scaleway, AliBaba Cloud, vSphere and Packet.net. That is nine of the fifteen registered providers, and the set is chosen for exactly the cases where a mock would prove nothing: whether a tag filter is applied correctly against a real cloud API, whether the right network interface is chosen for the address, whether the credential handling works with a real key.
This matters more for a discovery library than for most libraries. A discovery library that returns the wrong address does not throw an error, it returns a plausible wrong answer, and the failure surfaces later as a node that cannot join the cluster. The only way to catch that class of bug is to point the code at a real cloud and check what comes back.
The unit test side is conventional. The Makefile has a default target that runs copywriteheaders, lint and test in that order, with golangci-lint for linting and a test target that runs go test with the race detector and a 60 second timeout. The .copywrite.hcl file and the copywriteheaders target are how HashiCorp keeps licence headers on every file, which is the house style rather than a technical requirement.
The acceptance tests are the interesting part of the setup, and they are also the part with a cost, since they allocate billable cloud resources to run. A fork without cloud credentials can run the unit tests and nothing else.
Using the CLI, and using the library directly
The command line tool installs with a single command:
go get -u github.com/hashicorp/go-discover/cmd/discoverand runs with a provider configuration:
discover addrs provider=aws region=eu-west-1 ...That is the whole CLI surface described in the README: an addrs subcommand that takes the same configuration string the library takes. It is enough to check what a configuration resolves to before you commit it to a Consul or Vault config file, which is the main reason to install it at all.
The library is installed separately:
go get -u github.com/hashicorp/go-discoverAnd you can then either support discovery for all available providers or only for some of them, by choosing whether to use the empty Discover struct or to populate the Providers map yourself. The README gives the AWS and GCE only case explicitly, and shows the logger being constructed with a comment that points out using ioutil.Discard for no log output, before the configuration string is passed to d.Addrs along with the logger:
// support discovery for all supported providers
d := discover.Discover{}
// support discovery for AWS and GCE only
d := discover.Discover{
Providers : map[string]discover.Provider{
"aws": discover.Providers["aws"],
"gce": discover.Providers["gce"],
}
}
// use ioutil.Discard for no log output
l := log.New(os.Stderr, "", log.LstdFlags)
cfg := "provider=aws region=eu-west-1 ..."
addrs, err := d.Addrs(cfg, l)That Providers map is the mechanism for the Kubernetes case too. When you import the k8s provider package yourself, you get a provider value you can put in the map:
// Imports at top of file
import "github.com/hashicorp/go-discover/provider/k8s"
// support discovery for all supported providers
d := discover.Discover{}
// support discovery for AWS and GCE only
d := discover.Discover{
Providers : map[string]discover.Provider{
"k8s": &k8s.Provider{},
}
}So the library gives you a narrow decision: take everything registered, or take the subset you want. The `provider` key in the configuration string then selects among them at runtime.
The provider set is a historical record of the cloud
Read the provider list as history and it becomes informative. Aliyun, TencentCloud and Packet sit alongside AWS, Azure and GCE, which tells you the project has followed the Chinese and bare metal cloud markets with the same attention it gave AWS. SoftLayer, Triton and vSphere point at a different period, when the target cluster was frequently on-premises virtualisation rather than a public cloud, and the same is true of SRV and mDNS, which are not clouds at all but DNS based discovery for smaller deployments.
That breadth is the library's real value for its actual users. If you run a Consul cluster that spans AWS and a vSphere cluster, or that includes a Triton account, a single configuration language covers all of it, and the tag conventions do not change per provider in a way the operator has to learn separately.
The cost of that breadth is visible in the dependency list. The module requires the Azure SDK for Go, the AWS SDK v2 EC2 client, the Triton Go client, gophercloud for OpenStack, the Linode client, the Scaleway SDK, the packngo client for Packet, the SoftLayer client, the Tencent Cloud SDK for CVM, govmomi for vSphere, the Google Cloud provider module, and client-go for Kubernetes. Even the providers you never use are in the module graph unless you vendor around them, which is why the Providers map is a meaningful optimisation rather than a stylistic choice.
Some of those dependencies are old. The Aliyun client is pinned to a 2017 pseudo-version, the Scaleway SDK to a 2018 pre-release, the SoftLayer client to August 2018, and the Packet client to 2018. Kubernetes client-go is at v0.22.2. For a library whose stated purpose is to work with current cloud APIs, that is a genuine maintenance question, and it is part of why the README points new work at go-netaddrs.
Where go-discover stops being the right answer
The first limit is the one the project itself states. go-discover is feature complete, maintained on an as-need basis, and go-netaddrs is the actively maintained alternative for discovering IP addresses without tying the code to specific infrastructure. If you are writing new service discovery and you are not a Consul or Vault user, the project is telling you not to start here.
The second is the provider model itself. Configuration is a string of key=value pairs interpreted by a provider, and the provider list is fixed at compile time. Adding a cloud means writing a provider and registering it, which is a real amount of work against a cloud's API. The alternative approach, which is what go-netaddrs offers, is to decouple address discovery from the infrastructure by having each environment report its own addresses, rather than having a central component interrogate every cloud API. The difference in approach is where the credentials and the cloud API access live.
The third is the credential surface. A single configuration string carries a region, a tag key and value, and an access key id and secret. Passing that through a CLI argument puts a cloud credential into your shell history, and the README does not document a mechanism for reading credentials from a file or an environment variable, though the individual provider config options do exist as separate keys. That is a real operational concern for anything run in a shared environment.
The fourth is the test coverage boundary. Nine of the fifteen registered providers have acceptance tests against real resources. For the other six, including several that matter to specific segments of the user base, correctness rests on unit tests with mocked APIs, and a cloud that changes an API response shape is a bug that surfaces in production.
For a Consul or Vault operator who has been using this for years, none of that is a reason to migrate off it. The library does exactly what the product needs, the configuration is uniform across sixteen providers, and the as-need maintenance has still produced releases in June, July and September 2026. The judgement only matters if you are choosing a library today.
Editorial conclusion
Adopt go-discover when you already run Consul or Vault and need their service discovery to find nodes in a specific cloud, since the tag conventions and the provider set are exactly what those products expect. Do not adopt it as a general purpose address finder, because the README states it is feature complete, maintained on an as-need basis, and that go-netaddrs is the actively maintained solution for discovering IP addresses without tying to specific infrastructure. Before you build on it, read the note at the top of the README, and if you need the Kubernetes provider, remember that it is implemented but not registered by default, so you have to import and register it yourself.
Frequently asked questions
What does go-discover do?
It is a Go library and command line tool to discover IP addresses of nodes in cloud environments based on meta information like tags provided by the environment. The provider configuration is a list of key=val tuples, and the provider is selected through the `provider` key.
Is go-discover still actively maintained?
The README states that go-discover is considered feature complete and is currently maintained on an as-need basis for use with Vault and Consul, and that go-netaddrs is the actively maintained alternative for discovering IP addresses without tying to specific infrastructure. Releases v1.3.0, v1.4.0 and v1.5.0 were tagged in June, July and September 2026.
How do I use the go-discover command line tool?
Install it with `go get -u github.com/hashicorp/go-discover/cmd/discover`, then run `discover addrs provider=aws region=eu-west-1 ...` with the provider configuration you want to resolve.
Why do I have to register the Kubernetes provider manually?
The Kubernetes provider is implemented in the provider subdirectory but is not automatically registered, so that the client-go dependency is not imposed on every build. You import the k8s provider package and add it to the Discover struct's Providers map yourself.
How do I quote values in a go-discover provider configuration?
If either the key or the value contains a space, a backslash or double quotes, quote it with double quotes, and use a backslash to escape double quotes or a backslash itself. Duplicate keys are reported as an error.
Which cloud providers does go-discover support?
The registered providers are Aliyun, Amazon AWS, DigitalOcean, Google Cloud, Linode, mDNS, Microsoft Azure, OpenStack, Scaleway, SoftLayer, SRV, TencentCloud, Triton, vSphere and Packet, with Kubernetes implemented but not registered by default. Acceptance tests that allocate real resources exist for AWS, Azure, Google Cloud, DigitalOcean, Triton, Scaleway, AliBaba Cloud, vSphere and Packet.net.
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/hashicorp-go-discover)Was this useful?