A safety note about using (or having)
$GOPATH in Go 1.13
One of the things in the Go 1.13 release notes is a little note
about improved support for
go.mod. This is worth quoting in
more or less full:
GO111MODULEenvironment variable continues to default to
auto, but the
autosetting now activates the module-aware mode of the go command whenever the current working directory contains, or is below a directory containing, a
go.modfile — even if the current directory is within
The important safety note is that this potentially creates a confusing situation, and also it may be easy for other people to misunderstand what this actually says in the same way that I did.
Suppose that there is a Go program that is part of a module,
example.org/fred/cmd/bar (with the module being example.org/fred).
If you do '
go get example.org/fred/cmd/bar', you're fetching and
building things in non-module mode, and you will wind up with a
$GOPATH/src/example.org/fred VCS clone, which will have a
file at its root, ie
the fact that there is a
go.mod file right there on disk, re-running
go get example.org/fred/cmd/bar' while you're in (say) your home
directory will not do a module-aware build. This is because, as the
note says, module-aware builds only happen if your current directory
or its parents contain a
go.mod file, not just if there happens
to be a
go.mod file in the package (and module) tree being built.
So the only way to do a proper module aware build is to actually
be in the command's subdirectory:
cd $GOPATH/src/example.org/fred/cmd/bar go get
(You can get very odd results if you cd to
and then attempt to '
go get example.org/fred/cmd/bar'. The result
is sort of module-aware but weird.)
This makes it rather more awkward to build or rebuild Go programs
through scripts, especially if they involve various programs that introspect your existing
Go binaries. It's also easy to slip up and de-modularize a Go binary;
one absent-minded '
go get example.org/...' will do it.
In a way, Go modules don't exist on disk unless you're in their
directory tree. If that tree is inside
$GOPATH and you're not in
it, you have a plain Go package, not a module.
(If the directory tree is outside
$GOPATH, well, you're not doing
much with it without
cd'ing into it, at which point you have a
The easiest way to see whether a binary was built module-aware or
not is '
goversion -m PROGRAM'. If
the program was built module-aware, you will get a list of all of
the modules involved. If it wasn't, you'll just get a report of
what Go version it was built with. Also, it turns out that you can
build a program with modules without it having a
GO111MODULE=on go get rsc.io/goversion@latest
The repository has tags but no
go.mod. This also works on
repositories with no tags at all. If the program uses outside
packages, they too can be non-modular, and '
goversion -m PROGRAM'
will (still) produce a report of what tags, dates, and hashes they
Update: in Go 1.13, '
go version -m PROGRAM' also reports the
module build information, with module hashes included as well.
This does mean that in theory you could switch over to building all
third party Go programs you use this way. If the program hasn't
converted to modules you get more or less the same results as today,
and if the program has converted, you get their hopefully stable
go.mod settings. You'd lose having a local copy of everything in
$GOPATH, though, which opens up some issues.