blob: bb3bff9c5ce671c4bf26661e7166f5be0e32468e [file] [log] [blame]
# New module changes in Go 1.16
18 Feb 2021
Tags: modules, versioning
Summary: Go 1.16 enables modules by default, provides a new way to install executables, and lets module authors retract published versions.
Jay Conrod
##
We hope you're enjoying Go 1.16!
This release has a lot of new features, especially for modules.
The [release notes](https://golang.org/doc/go1.16) describe these changes briefly, but let's explore a few of them in depth.
## Modules on by default
The `go` command now builds packages in module-aware mode by default, even when no `go.mod` is present.
This is a big step toward using modules in all projects.
It's still possible to build packages in GOPATH mode by setting the `GO111MODULE` environment variable to `off`.
You can also set `GO111MODULE` to `auto` to enable module-aware mode only when a go.mod file is present in the current directory or any parent directory.
This was previously the default.
Note that you can set `GO111MODULE` and other variables permanently with `go env -w`:
go env -w GO111MODULE=auto
We plan to drop support for GOPATH mode in Go 1.17.
In other words, Go 1.17 will ignore `GO111MODULE`.
If you have projects that do not build in module-aware mode, now is the time to migrate.
If there is a problem preventing you from migrating, please consider filing an [issue](https://github.com/golang/go/issues/new) or an [experience report](https://github.com/golang/go/wiki/ExperienceReports).
## No automatic changes to go.mod and go.sum
Previously, when the `go` command found a problem with `go.mod` or `go.sum` like a missing `require` directive or a missing sum, it would attempt to fix the problem automatically.
We received a lot of feedback that this behavior was surprising, especially for commands like `go list` that don't normally have side effects.
The automatic fixes weren't always desirable: if an imported package wasn't provided by any required module, the `go` command would add a new dependency, possibly triggering upgrades of common dependencies.
Even a misspelled import path would result in a (failed) network lookup.
In Go 1.16, module-aware commands report an error after discovering a problem in `go.mod` or `go.sum` instead of attempting to fix the problem automatically.
In most cases, the error message recommends a command to fix the problem.
$ go build
example.go:3:8: no required module provides package golang.org/x/net/html; to add it:
go get golang.org/x/net/html
$ go get golang.org/x/net/html
$ go build
As before, the `go` command may use the `vendor` directory if it's present (see [Vendoring](https://golang.org/ref/mod#vendoring) for details).
Commands like `go get` and `go mod tidy` still modify `go.mod` and `go.sum`, since their main purpose is to manage dependencies.
## Installing an executable at a specific version
The `go install` command can now install an executable at a specific version by specifying an `@version` suffix.
go install golang.org/x/tools/gopls@v0.6.5
When using this syntax, `go install` installs the command from that exact module version, ignoring any `go.mod` files in the current directory and parent directories.
(Without the `@version` suffix, `go install` continues to operate as it always has, building the program using the version requirements and replacements listed in the current module’s `go.mod`.)
We used to recommend `go get -u program` to install an executable, but this use caused too much confusion with the meaning of `go get` for adding or changing module version requirements in `go.mod`.
And to avoid accidentally modifying `go.mod`, people started suggesting more complex commands like:
cd $HOME; GO111MODULE=on go get program@latest
Now we can all use `go install program@latest` instead.
See [`go install`](https://golang.org/ref/mod#go-install) for details.
In order to eliminate ambiguity about which versions are used, there are several restrictions on what directives may be present in the program's `go.mod` file when using this install syntax.
In particular, `replace` and `exclude` directives are not allowed, at least for now.
In the long term, once the new `go install program@version` is working well for enough use cases, we plan to make `go get` stop installing command binaries.
See [issue 43684](https://golang.org/issue/43684) for details.
## Module retraction
Have you ever accidentally published a module version before it was ready?
Or have you discovered a problem right after a version was published that needed to be fixed quickly?
Mistakes in published versions are difficult to correct.
To keep module builds deterministic, a version cannot be modified after it is published.
Even if you delete or change a version tag, [`proxy.golang.org`](https://proxy.golang.org) and other proxies probably already have the original cached.
Module authors can now *retract* module versions using the `retract` directive in `go.mod`.
A retracted version still exists and can be downloaded (so builds that depend on it won't break), but the `go` command won’t select it automatically when resolving versions like `@latest`.
`go get` and `go list -m -u` will print warnings about existing uses.
For example, suppose the author of a popular library `example.com/lib` releases `v1.0.5`, then discovers a new security issue.
They can add a directive to their `go.mod` file like the one below:
// Remote-triggered crash in package foo. See CVE-2021-01234.
retract v1.0.5
Next, the author can tag and push version `v1.0.6`, the new highest version.
After this, users that already depend on `v1.0.5` will be notified of the retraction when they check for updates or when they upgrade a dependent package.
The notification message may include text from the comment above the `retract` directive.
$ go list -m -u all
example.com/lib v1.0.0 (retracted)
$ go get .
go: warning: example.com/lib@v1.0.5: retracted by module author:
Remote-triggered crash in package foo. See CVE-2021-01234.
go: to switch to the latest unretracted version, run:
go get example.com/lib@latest
For an interactive, browser-based guide, check out [Retract Module Versions](https://play-with-go.dev/retract-module-versions_go116_en/) on [play-with-go.dev](https://play-with-go.dev/).
See the [`retract` directive docs](https://golang.org/ref/mod#go-mod-file-retract) for syntax details.
## Controlling version control tools with GOVCS
The `go` command can download module source code from a mirror like [proxy.golang.org](https://proxy.golang.org) or directly from a version control repository using `git`, `hg`, `svn`, `bzr`, or `fossil`.
Direct version control access is important, especially for private modules that aren't available on proxies, but it's also potentially a security problem: a bug in a version control tool may be exploited by a malicious server to run unintended code.
Go 1.16 introduces a new configuration variable, `GOVCS`, which lets the user specify which modules are allowed to use specific version control tools.
`GOVCS` accepts a comma-separated list of `pattern:vcslist` rules.
The `pattern` is a [`path.Match`](https://golang.org/pkg/path#Match) pattern matching one or more leading elements of a module path.
The special patterns `public` and `private` match public and private modules (`private` is defined as modules matched by patterns in `GOPRIVATE`; `public` is everything else).
The `vcslist` is a pipe-separated list of allowed version control commands or the keyword `all` or `off`.
For example:
GOVCS=github.com:git,evil.com:off,*:git|hg
With this setting, modules with paths on `github.com` can be downloaded using `git`; paths on `evil.com` cannot be downloaded using any version control command, and all other paths (`*` matches everything) can be downloaded using `git` or `hg`.
If `GOVCS` is not set, or if a module does not match any pattern, the `go` command uses this default: `git` and `hg` are allowed for public modules, and all tools are allowed for private modules.
The rationale behind allowing only Git and Mercurial is that these two systems have had the most attention to issues of being run as clients of untrusted servers.
In contrast, Bazaar, Fossil, and Subversion have primarily been used in trusted, authenticated environments and are not as well scrutinized as attack surfaces.
That is, the default setting is:
GOVCS=public:git|hg,private:all
See [Controlling version control tools with `GOVCS`](https://golang.org/ref/mod#vcs-govcs) for more details.
## What's next?
We hope you find these features useful. We're already hard at work on the next set of module features for Go 1.17, particularly [lazy module loading](https://github.com/golang/go/issues/36460), which should make the module loading process faster and more stable.
As always, if you run into new bugs, please let us know on the [issue tracker](https://github.com/golang/go/issues). Happy coding!