Go 1.11 Modules

Go 1.11 will add preliminary support for versioned modules as proposed here.

Go modules will be an experimental opt-in feature in Go 1.11, with the hope of incorporating feedback and finalizing the feature for Go 1.12. Even though the details may change, future releases will support modules defined using Go 1.11 or vgo.

Current Status

  • The recent work by the Go team on versioned Go modules started outside of the main Go repository with the vgo tool, but on July 12, 2018 support for versioned Go modules landed in the main Go repository (announcement thread).
    • Development work on modules is now occurring exclusively in the main Go repository, with a periodic export to the vgo repository for people still using vgo.
  • Beta support for modules is now also available starting with Go 1.11 beta 2 (released on July 20, 2018).
  • On July 31, 2018, there was a significant change in master for the go mod commands. See faq below for an overview.

NOTE: One current significant issue is that some older versions of git are not working:

  • #26501 covers git 2.10.0 and earlier not working (fixed in master but not fixed in 1.11 beta2).
  • #26594 appears to be different problem but might be related to older git as well.

Installing and Activating Module Support

To use modules, you currently have three install options:

As of July 23, 2018, there are some recommendations (e.g., here) to currently prefer installing from source or the latest beta over using vgo.

Once installed, you can then activate module support in one of three ways:

  • Invoke the go command in a directory outside of the $GOPATH/src tree, with a valid go.mod file in the current directory or any parent of it and the environment variable GO111MODULE unset (or explicitly set to auto).
  • Invoke the go command with GO111MODULE=on in the command environment.
  • Invoke the binary named vgo (if you have installed vgo from the subrepository).

New Concepts

Major Versions

Go modules must be semantically versioned in the form v(major).(minor).(patch) (for example, v0.1.0, v1.2.3, or v3.0.1). If using Git, tag released commits with their versions. (Stand-alone distributed module repositories, such as Project Athens, are in the works.)

The major version of a module must be included in both the module path and the package import path if the major version is v2 or higher. Module versions of v1 and v0 must not be included in the path. Modules with different paths are different modules. Thus me.io/my/mod is different than me.io/my/mod/v2 and both may be imported in a single build, which among other benefits allows a v1 module to be implemented in terms of its v2 replacement or vice versa.

The behavior of modules for existing packages with post-v1 tags is still in flux; an important related recent change was issue 26238, which substantially improved the behavior for existing packages with post-v1 tags.

Modules

Go packages now live in modules. The path of a module is a URL path where it may be found, and may include a major version at the end of the path (but nowhere else). Module source code may be located outside of $GOPATH. Two example modules are rsc.io/goversion and github.com/kardianos/vtest/v3.

Modules are defined by a go.mod file that lives in the root of the module. Module files may include comments and will look familiar to a go programmer. Here is an example go.mod file:

module github.com/kardianos/vmain/v3

require (
    github.com/kardianos/vtest/v2 v2.0.2
)

There are 4 directives: “module”, “require”, “exclude”, “replace”. Module paths may be quoted but are not required to be.

Including major versions in import paths will produce incompatibilities with old versions of Go. To work around this prior versions of the go tool have been updated and released to continue building as before. (See issue 25069.)

exclude and replace directives only operate on the current (“main”) module. exclude and replace directives in modules other than the main module are ignored.

TODO: show example exclude and replace directives.

There are two ways to release a v2 (or higher) module version:

  1. Create a v2 directory and place a new go.mod file in that folder. The module path must end with /v2. Tag the release with v2.0.0.
  2. Update the go.mod file to include a /v2 at the end of the module path. Tag the release with v2.0.0.
    • To avoid confusion with this approach, consider putting the v2.*.* commits on a separate v2 branch.

Packages are imported relative to the full module path, for example:

  • import "me.io/my/mod/v2/pkg" for package pkg in module me.io/my/mod/v2
  • import "me.io/my/mod/pkg" for package pkg in module me.io/my/mod (v1 or v0).

Version Selection

The default behavior when adding a new direct dependency via go commands such as ‘go get’ or ‘go build’ is to select the latest tagged release version (such as ‘v1.2.3’), which is recorded in the go.mod file with a require directive (such as require D v1.2.3). The minimal version selection algorithm is used to select the actual versions used in a build.

In general, the version of each module selected by minimal version selection and used in a build is always the semantically highest of the versions explicitly required by the module or one of its dependencies. This effectively locks versions into place until the module author or user chooses a new version explicitly or chooses to upgrade to the latest available minor or patch version.

For a brief overview and rationale for the minimal version selection algorithm, see the “High Fidelity Builds” section of the official proposal, or the more detailed vgo blog series.

Different major versions are distinct modules. For example, a /v2 module will never be compared with a /v3 module during minimal version selection.

To see a list of the selected module versions, use go list -m.

See also the “Upgrading and Downgrading Dependencies” section below and the “How are versions marked as incompatible?” FAQ below.

Defining a Module

To create a go.mod for an existing project:

  1. Navigate to the root of the module's source tree and activate module mode in the go command:

    $ cd $GOPATH/src/<project path>
    $ export GO111MODULE=on
    

    or:

    $ cd <project path outside $GOPATH/src>
    
  2. Create the initial module definition and write it to the go.mod file:

    # if using go1.11beta2 or vgo:
    $ go mod -init                
    
    # if using 'master', use the newer form:  
    $ go mod init                     
    

    This step converts from any existing dep Gopkg.lock file or from any of the other nine total supported dependency formats, adding require statements to match the existing configuration.

    If go mod cannot determine an appropriate package path, or if you need to override that path, use the -module flag:

    # if using go1.11beta2 or vgo:
    $ go mod -init -module example.com/my/module/v2    
    
    # if using 'master':  
    $ go mod init example.com/my/module/v2
    
  3. Build the module. This will automatically add missing or unconverted dependencies as needed to satisfy imports for this particular build invocation:

    $ go build ./...
    
  4. Test the module as configured to ensure that it works with the selected versions:

    $ go test ./...
    
  5. (Optional) Run the tests for all imported modules (direct and indirect dependencies) to check for incompatibilities:

    $ go test all
    

Prior to tagging a release, see the Preparing a release section below.

Upgrading and Downgrading Dependencies

Day-to-day adding, removing, upgrading, and downgrading of dependencies should be done using ‘go get’, which will automatically update the go.mod file.

In addition, go commands like ‘go build’, ‘go test’, or even ‘go list’ will automatically add new dependencies as needed to satisfy imports (updating go.mod and downloading the new dependencies).

To upgrade to the latest version for all transitive dependencies of the current module:

  • run go get -u to use the latest minor or patch releases
  • run go get -u=patch to use the latest patch releases

To upgrade or downgrade to a more specific version, ‘go get’ allows version selection to be overridden by adding an @version suffix or “module query” to the package argument, such as go get github.com/gorilla/mux@v1.6.2, go get github.com/gorilla/mux@e3702bed2, or go get github.com/gorilla/mux@'<v1.6.2'.

See the “Module-aware go get” and “Module queries” sections of the tip documentation for more information on the topics here.

After upgrading or downgrading any dependencies, you may then want to run the tests again for all imported modules (direct and indirect dependencies) to check for incompatibilities:

$ go test all

Preparing a release

Best practices for creating a release of a module are expected to emerge as part of the initial modules experiment. Many of these might end up being automated by a future ‘go release’ tool.

Some current suggested best practices to consider doing prior to tagging a release:

  • Run go mod -sync (or if using master: go mod tidy) to ensure your current go.mod reflects all possible build tags/OS/architecture combinations (as described here) and possibly prune any extraneous requirements (as described here).

  • Run go test all to test your module (including your direct and indirect dependencies) as a way of validating that the currently selected packages versions are compatible.

    • The number of possible version combinations in general is exponential in the number of modules, so you cannot expect your dependencies to have tested against all possible combinations of their dependencies.
    • As part of the modules work, go test all has been re-defined to be more useful to include all the packages in the current module, plus all the packages they depend on through a sequence of one or more imports, while excluding packages that don't matter in the current module.

Additional Resources

Documentation and Proposal

  • Official documentation:
    • Latest HTML documentation for modules on tip.golang.org
    • Run go help modules for more about modules. (This is the main entry point for modules topics via go help)
    • Run go help mod for more about the go mod command.
    • Run go help module-get for more about the behavior of go get when in module-aware mode.
    • Run go help goproxy for more about the module proxy, including a pure file-based option via a file:/// URL.
  • The initial “Go & Versioning” series of blog posts on vgo by Russ Cox (first posted February 20, 2018)
  • Official golang.org blog post introducing the proposal (March 26, 2018)
    • This provides a more succinct overview of the proposal than the full vgo blog series, along with some of the history and process behind the proposal
  • Official Versioned Go Modules Proposal (last updated March 20, 2018)

Introductory Material

Additional Material

Issues

FAQ

How are versions marked as incompatible?

The require directive allows any module to declare that it should be built with version >= x.y.z of a dependency D (which may be specified due to incompatibilities with version < x.y.z of module D). Empirical data suggests this is the dominant form of constraints used in dep and cargo. In addition, the top-level module in the build can exclude specific versions of dependencies or replace other modules with different code. See the full proposal for more details and rationale.

One of the key goals of the versioned modules proposal is to add a common vocabulary and semantics around versions of Go code for both tools and developers. This lays a foundation for future capabilities to declare additional forms of incompatibilities, such as:

  • declaring deprecated versions as described in the initial vgo blog series
  • declaring pair-wise incompatibility between modules in an external system as discussed for example here during the proposal process
  • declaring incompatible versions or insecure versions of a module after a release has been published. See for example the on-going discussion in #24031

What are some of the biggest changes since the initial vgo proposal?

Here is a sample list of improvements, almost all of which were primarily driven by community feedback:

  • Top-level vendor support was retained rather than vgo-based builds ignoring vendor directories entirely (discussion, CL)
  • Backported minimal module-awareness to allow older Go versions 1.9.7+ and 1.10.3+ to more easily consume modules for v2+ projects (discussion, CL)
  • Added support via command go get -u=patch to update all transitive dependencies to the latest available patch-level versions on the same minor version (discussion, documentation)
  • Allowed use of existing v2+ packages that don't yet have go.mod (disallowed in initial vgo proposal; recent update in related behavior described here)
  • Allowed more flexible replace directives (CL)
  • Added additional ways to interrogate modules (for human consumption, as well as for better support for editor / IDE integration)
  • The UX of the go CLI has continued to be refined based on experiences so far (e.g., #26581, CL)
  • Additional control via environmental variables (e.g., GOFLAGS in #26585, CL)
  • Most likely: additional support for warming caches for use cases such as CI or docker builds (#26610)
  • Most likely: better support for installing specific versions of programs to GOBIN (#24250)

As part of the proposal, prototype, and beta process, there have been over 400 issues created by the overall community. Please continue to supply feedback.

How have the go mod commands changed recently in master?

As of July 31, 2018, there has been a significant change in master for the go mod commands. These changes are not in go1.11beta2. Two snippets from the CL briefly covering the rationale and the list of new vs. old commands:

The current "go mod" command does too many things.

It looks like "everything you might want to do with modules"
which causes people to think all module operations go through
"go mod", which is the opposite of the seamless integration we're
going for. In particular too many people think "go mod -require"
and "go get" are the same.

and:

split "go mod" into multiple subcommands:

	go mod edit   # old go mod -require ...
	go mod fix    # old go mod -fix
	go mod graph  # old go mod -graph
	go mod init   # old go mod -init
	go mod tidy   # old go mod -sync
	go mod vendor # old go mod -vendor
	go mod verify # old go mod -verify

Splitting out the individual commands makes both the docs
and the implementations dramatically easier to read.
It simplifies the command lines
(go mod -init -module m is now 'go mod init m')
and allows command-specific flags.

Additional frequently asked questions

  • Please see the earlier FAQ from the official proposal discussion, including answers to common question such as:
    • “Won't minimal version selection keep developers from getting important updates?”
    • “Why are major versions v0, v1 omitted from import paths?”
    • “Why must major version numbers appear in import paths?”