Library / SDK
hashicorp/go-getter avatar
hashicorp/go-getter

go-getter makes one URL string work across six protocols, and warns you about SSRF

Package for downloading things from a string URL using a variety of protocols.

1,826 stars276 forksGoMPL-2.0

At a glance

What is it?
HashiCorp's go-getter takes a single string and resolves it to a download from a file, Git, Mercurial, HTTP, S3 or GCS source, with detectors that guess the protocol, forced-protocol syntax to override them, double-slash subdirectory selection, and checksum verification that only works for files.
Who is it for?
Adopt go-getter if your product takes a user-supplied source string and needs to fetch from several kinds of origin behind one interface, since the detectors and client modes remove real code from the caller and Terraform and Nomad already depend on it that way.
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 1 day 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

One string in, a download out

go-getter is a library for downloading files or directories using a URL as the primary form of input. The stated value is flexibility: downloading from file paths, Git, HTTP, Mercurial and other sources using a single string, which removes the burden of knowing how to download from a variety of sources from the implementer.

That is the whole abstraction, and it is the reason the package exists. It is used by Terraform to download modules and by Nomad to download binaries, which is the reference case: infrastructure products where a user writes a short string and the tool has to cope with whatever kind of repository that turned out to be.

Installation is ordinary.

bash
$ go get github.com/hashicorp/go-getter

And there is a command that exists for exactly one purpose, testing URL strings.

bash
$ go install github.com/hashicorp/go-getter/cmd/go-getter
bash
$ go-getter github.com/foo/bar ./foo

The README calls the command useful for verifying URL structures, and for a library whose input is a string with modifiers in it, that is the debugging tool you will use most.

Detectors guess, forced protocols override

Detectors are the feature that makes the string input pleasant. A detector takes a URL, possibly an invalid one, and transforms it into a proper URL if it matches a pattern.

Four are built in. File paths such as ./foo become absolute file URLs. GitHub URLs such as github.com/mitchellh/vagrant become Git over HTTP. GitLab URLs such as gitlab.com/inkscape/inkscape become Git over HTTP. BitBucket URLs such as bitbucket.org/mitchellh/vagrant become Git or Mercurial using the BitBucket API, which is the one detector that calls out to a hosting service rather than pattern-matching alone.

Detectors are extensible, and protocols are extensible through the Getter interface, so an application can add both a new protocol and a new detector.

Forced protocol syntax exists because some URLs are ambiguous. http://github.com/mitchellh/vagrant.git could be an HTTP download or a Git clone, and the answer is to prefix the protocol with double colons.

code
git::http://github.com/mitchellh/vagrant.git

That download uses the Git protocol, and forced protocol also overrides any detector that would otherwise have chosen. Without it, the GitHub detector would have picked Git anyway, which is exactly the ambiguity the syntax resolves.

Options live in the URL, subdirectories live behind a double slash

Protocol-specific options are query parameters on the URL, which means configuration and location travel together in one string. The git protocol, for instance, supports a ref query parameter naming what ref to check out.

code
github.com/hashicorp/go-getter?ref=abcd1234

That is convenient and it is also the thing to watch, because the same mechanism means a caller-supplied string can carry parameters the caller did not intend.

Subdirectories use a double slash after the source URL.

code
https://github.com/hashicorp/go-getter.git//testdata

go-getter downloads the whole thing as if the double slash were absent, then copies only the path after it into the target directory. The README's example is concrete about the result: downloading that URL into /tmp leaves /tmp/archive.gz, which lives in testdata upstream but arrives at the top of the target because only that directory was copied.

Glob patterns are allowed, with a constraint worth remembering: the pattern must match exactly one entry or go-getter returns an error. So a pattern is a convenience when you know the name follows a predictable structure, and a hard failure when it matches nothing or matches twice.

Checksums cover files, not directories

go-getter can verify a checksum automatically for you, and the boundary is stated up front: checksumming only works for downloading files, not directories, though it works for any protocol.

The mechanism is a checksum query parameter appended to the URL, with the expected value in it.

That asymmetry has consequences for how you use the library. If your users point at a Git repository, you get a directory and no checksum verification, which means your integrity story for that case has to come from somewhere else, such as pinning a ref. If they point at a release archive, you get a file and verification, provided you supply the expected hash rather than letting it be computed from what you just downloaded.

The decompressor list in the repository shows how wide the file handling is, with separate source files for gzip, bzip2, tar, tbz2, tgz, txz, tzst, xz, zip and zstd, plus a common decompress.go and copy_dir.go for the directory case. So the file path is well trodden and the directory path is structurally different, which is consistent with the checksum rule.

The security section is the most important part of the README

go-getter opens with a warning that deserves to be read before any code is written.

Fetching resources from user-supplied URLs is an inherently dangerous operation and may leave your application vulnerable to server side request forgery, path traversal, denial of service or other flaws. The library contains mitigations for some of these issues but should still be used with caution in security-critical contexts, and it points to security options that can be configured to mitigate some of these risks.

Some, not all. That is the sentence to hold on to.

There is a second, more specific warning that is easy to miss because it comes after the first. go-getter may return values that contain caller-provided query parameters that can contain sensitive data. Context around what parameters are and are not sensitive is known only by the caller, and is specific to each use case. The recommendation is to ensure go-getter's return values, error messages for example, are properly handled and sanitised so sensitive data is not persisted to logs.

That is a real operational obligation on the caller. A signed download URL with a token in a query parameter may have that token appear in an error string if the fetch fails, so callers should sanitise returned values before logging them.

The dependency list explains what the protocols cost

go.mod shows what supporting six protocols means in dependencies, and it is heavier than the API suggests.

Cloud storage comes through the official clients: cloud.google.com/go/storage v1.69.0 with google.golang.org/api v0.301.0 for Google Cloud, and the AWS SDK v2 with aws-sdk-go-v2/config, credentials, feature/ec2/imds and service/s3 v1.114.1, plus a HashiCorp aws-sdk-go-base layer for the authentication flows.

Compression is handled by klauspost/compress v1.20.1 with ulikunitz/xz alongside it, which covers most of the archive formats without shelling out to the system.

Smaller pieces have specific jobs: bgentry/go-netrc for credential files, hashicorp/go-version for version constraints, hashicorp/go-cleanhttp for a default-clean HTTP client, mitchellh/go-homedir for resolving home directories, cheggaaa/pb for progress bars, and golang.org/x/oauth2 for token flows.

That last cluster is what makes a signing URL or an authenticated repository work without you wiring it. The trade is that importing the package pulls both cloud SDKs into your build, whether or not you use those protocols, and there is a client_mode.go suggesting separate modes for clients with restricted functionality.

Around the code are .golangci.yaml for linting, .goreleaser.yml for releases, .go-version pinning the toolchain, and a .release/ directory, plus per-protocol detect_*.go files with their own tests, which is what you would expect from a package whose whole surface is pattern matching.

Editorial conclusion

Adopt go-getter if your product takes a user-supplied source string and needs to fetch from several kinds of origin behind one interface, since the detectors and client modes remove real code from the caller and Terraform and Nomad already depend on it that way. Do not adopt it for anything security-critical without reading its own security section first: the library warns about server side request forgery, path traversal and denial of service, contains mitigations for only some of them, and returns error values that can echo your caller-supplied query parameters back into your logs. Verify first that your Go version matches the line you pin, since v1.8.10 and v2.2.5 were both released on 2026-10-06 and the two lines differ, and that you configure the security options rather than relying on defaults.

Frequently asked questions

How do I install go-getter?

Use go get github.com/hashicorp/go-getter. To test URL strings, install the command with go install github.com/hashicorp/go-getter/cmd/go-getter and run it with a source and a destination, for example go-getter github.com/foo/bar ./foo.

Which protocols does go-getter support?

Local files, Git, Mercurial, HTTP, Amazon S3 and Google GCP out of the box. Additional protocols can be added at runtime by implementing the Getter interface, and detectors are extensible as well.

How do I download only a subdirectory with go-getter?

Put a double slash after the source URL and give the subdirectory after it, as in https://github.com/hashicorp/go-getter.git//testdata. go-getter downloads the source as usual and then copies only that directory into the target. Glob patterns are allowed but must match exactly one entry or it returns an error.

Does go-getter verify checksums for directory downloads?

No. Checksumming works for file downloads of any protocol by appending a checksum query parameter, but it does not work for directories.

What security risks does go-getter carry?

The README warns that fetching from user-supplied URLs can leave an application open to server side request forgery, path traversal and denial of service, and that go-getter mitigates some of these but not all. It also warns that return values can contain caller-supplied query parameters that may be sensitive, so error messages should be sanitised before they reach logs.

Official sources

  1. hashicorp/go-getter on GitHub
  2. Issues
  3. License: MPL-2.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hashicorp-go-getter.svg)](https://hysenlabs.com/projects/hashicorp-go-getter)

Was this useful?