DEV Community

Cover image for Why is GO111MODULE everywhere, and everything about Go Modules (updated with Go 1.20)

Why is GO111MODULE everywhere, and everything about Go Modules (updated with Go 1.20)

Maël Valais on November 13, 2019

You might have noticed that GO111MODULE=on is flourishing everywhere. Many readmes have that: GO111MODULE=on go get golang.org/x/tools/gopls@lat...
Collapse
 
daodennis profile image
daodennis

Thank you for this article Maël!
You might find this as a breath of fresh air, regarding "Remember that go get also updates your go.mod"
: groups.google.com/g/golang-tools/c...
go build, go test, and others - stop updating go.mod by default

Seems like there is a flag that certain Go tools have, the "-mod=readonly" flag. Might be worth adding to your article.

Collapse
 
alexshtin profile image
Alex Shtin • Edited

Great post, thanks for sharing. One question. We use GO111MODULE=off to install tools like goimport and not to pollute our go.mod file:

GO111MODULE=off go get -u golang.org/x/tools/cmd/goimports
Enter fullscreen mode Exit fullscreen mode

How is it worse than:

(cd && GO111MODULE=on go get -u golang.org/x/tools/cmd/goimports)
Enter fullscreen mode Exit fullscreen mode

?

Collapse
 
maelvls profile image
Maël Valais

Using GO111MODULE=off, you are falling back on the GOPATH method of installing the binary. In GOPATH mode, the master branch is always going to be the one checked out.

With GO111MODULE=on, you can rely on versions (i.e, git tags). The command

(cd && GO111MODULE=on go get -u golang.org/x/tools/cmd/goimports)
Enter fullscreen mode Exit fullscreen mode

will fetch the latest tag. The great benefit of this method is that you can pin-point the version to a branch or a tag or a commit:

(cd && GO111MODULE=on go get -u golang.org/x/tools/cmd/goimports@2363391)
Enter fullscreen mode Exit fullscreen mode

And since Go 1.16, the command has been greatly simplified (as long as there is no replace directive in goimport's go.mod):

go install golang.org/x/tools/cmd/goimports@2363391
Enter fullscreen mode Exit fullscreen mode
Collapse
 
suntong profile image
suntong • Edited

That's such a helpful post, so many of my questions got answered here. One more:

With go mod vendor no need to pass Github credentials to the docker build context. We can just put everything in vendor/ and the problem is solved.

I haven't fully got this working yet. Could you elaborate more on this a bit more please?

  • what go mod vendor is actually doing, how would it be different without doing it? Would -mod=vendor work without such step? and, -mod=vendor is for go build right?
  • how to put things in vendor/? Can you give a detailed example please -- i.e., Should I put mine in the GOPATH way, or the go mod way (with twisted name and added versions), Can I not put everything, but only a selectful of them that go get is failing to get?

Thanks

Collapse
 
maelvls profile image
Maël Valais

Hi! Thanks for the kind words!!! 🙂

  • go mod vendor will vendor all the .go files that are imported by your project (it is smart and only vendors the files actually used, not the whole repo for each import path). It keeps track of what is being vendored in vendor/modules.txt (not sure but I think this module list is only "for the humans" so that we can see in a diff what import paths have been added to vendor/)
  • To put things into vendor/, you first need to have modules turned on (go.mod at the root of your project) and then you can run go mod vendor once and here you go. Whenever you add import paths in your project, you also want to re-run go mod vendor to add/delete any missing/unused vendored files.
  • After having run go mod vendor you can fall back to using the good old GOPATH way (i.e. GO111MODULE=off) and not care about modules anymore.
  • Before Go 1.14, go build would by default use the modules in $GOPATH/pkg/mod instead of vendor/ and you had to run go build -mod=vendor
  • With Go 1.14 and above, the vendor/ folder is used by default and if you want to force using the $GOPATH/pkg/mod you can use go build -mod=mod.

Should I put my vendor/ in the GOPATH way or the go mod way

I think go mod vendor puts things in the GOPATH way (except it only puts the files that are "actually used"). Not sure I answered the question properly though 😞

Can I not put everything, but only a selectful of them that go get is failing to get?

Ah, right, I see the use case: you want to be able to manually add anything that go get doesn't know how to download (e.g. private networks, corporate firewalls).

I guess you can definitely do that: go mod vendor for anything that works and manually copy-paste the import paths that are failing. I guess you would have to update vendor/modules.txt too but not sure. The important part is that the hash of the files you manually add must match the hashes in the go.sum (I guess). 👍

Collapse
 
suntong profile image
suntong

Thanks a lot for such detailed explanation.

Collapse
 
domq profile image
domq • Edited

Thanks Maël, you single-handedly saved me about 8 hours of RTFM. Now I can get started on a project that enjoys sane, 21st-century style version control of its dependencies. And thanks for the direnv link, which appears to work with Emacs (although I can't vouch for that just yet)

Collapse
 
murphyke profile image
Kevin Murphy

Hi, your example able says use replace github.com/maelvls/beers => ../beers ... but I think the word use is not supposed to be there. Thanks for the post, btw.

Collapse
 
maelvls profile image
Maël Valais

Good point, thank you!!
I fixed that in the article 👍

Collapse
 
sandeepmeenuga profile image
sameen

Would you share something about govendor(github.com/kardianos/govendor) vs Go111module=on . I've a doubt about Go111module=on which saves one version of packages only in GOPATH but Govendor works as individual project's versions which exactly as node_modules. Any views appreciated.

Collapse
 
maelvls profile image
Maël Valais • Edited

Hi sameen,

Unfortunately, I do not know about govendor. But from what I understand, when building a binary with GO111MODULE=on, a single version of each dependency will be used for the whole build. Russ Cox calls it minimal version selection (see his blog post on Dec 3rd, 2019).

I've a doubt about Go111module=on which saves one version of packages only in GOPATH

What do you mean? GO111MODULE=on will remember (in go.sum) the version of dependencies and save each dependency copy in GOPATH/pkg/mod (i.e. one git clone at a fixed version if you will).

Note that GO111MODULE=on works very differently from node_modules since a single version is used per package, even when the package is used in multiple dependencies across the dependency tree.

Collapse
 
kelepirci profile image
Ferhat Ozkasgarli • Edited

What a software language. A simple start require great effort and time. It must be great to become GO developer ( ͡° ͜ʖ ͡°).

Wanderful article to sooth my pain while I was trying to figure out the GOPATH and its minions. :D

I thank and salute your sir ...

Collapse
 
rafalskolasinski profile image
RafalSkolasinski

It could be good to add note on behaviour in Go 1.14. Does it differ from one in Go 1.13?

Collapse
 
maelvls profile image
Maël Valais

Definitely, I’ll try to find time to update to 1.14 🙂

Collapse
 
rafalskolasinski profile image
RafalSkolasinski

Awesome!
BTW, this is a go to post about understanding GO111MODULES. IMO should be linked / part of official docs.

Collapse
 
maelvls profile image
Maël Valais

Done! I updated with 1.14 and two "new" pitfalls 🙂

Collapse
 
martinflower profile image
Martin Flower • Edited

Thanks Maël

Maybe you can answer the following, related, question:

If I'm using Go 1.14, with go.mod, no vendor folder, should I have a GOPATH environment variable? Does this affect GO111MODULE in any way?

Thanks

/Martin

Collapse
 
1oglop1 profile image
Jan Gazda

Reading the discussion I'm glad I'm not a lone who find Go things counter intuitive.
This article has helped me to solve the problem when go get did not create binary and exited with success.

Collapse
 
gcdcoder profile image
Gustavo Castillo

Great article thanks for sharing.

Collapse
 
folkengine profile image
Chris Baker

This was really useful. Thanks!

Collapse
 
themrkumar profile image
themrkumar

Great Article. Please also make a tutorial about Go modules

Collapse
 
benkame profile image
Ben Ka

Very helpful! That spares me lot of pain.

Collapse
 
jy226 profile image
Jaafar Yahya

Great Article !

Collapse
 
johanpiquet profile image
Johan PIQUET

Thank you, interesting!

Collapse
 
xmpace profile image
yema

Helps me a lot, thank you!

Collapse
 
srap profile image
Sravya

Wonderful post, saves a ton of time, I Signed up to dev.to to like your post and follow :)

Keep inspiring, Thank you