Golang learning journal — (3) go commands — go get, go install, go mod download, go mod tidy — when to use what?

Shelly
6 min readOct 17, 2022

--

Photo by Letizia Bordoni on Unsplash

Introduction

Hi there! I am Shelly, a non-CS background developer since 2020. This article belongs to my Golang learning journal series. For all the related articles, you can find the links in the table of contents at the very first article of this series.

Overchoice

For new go developers, it is very confusing to see so many similar commands that can be used to download packages or modules (P.S. — a module is a collection of packages). They are go get , go install , go mod download , and go mod tidy . To understand the differences between them, we first need to understand the history of them.
However, before going to the lengthy history details, let me first show you a comparison table and summarise when we should use which command in the next section.

P.S. For some JavaScript developers,go.modis similar to package.json & go.sum is similar to package-lock.json, but NOT exactly.
However, as package.json & package-lock.json, both go.mod & go.sum files should be checked into git.

Comparison

Below is a quick comparison of each command.
For the download location, module cachemeans $GOPATH/pkg/mod/cache/download . People also call module cache“local directory storing downloaded modules”.
On the other hand, GOBINmeans $GOPATH/bin .

Go commands summary table

When to use what

Let’s start with the most common used commands, and slowly go to the least used ones.

go mod tidy — this is the most universal used commands.
It is very common that, when downloading any non-standard packages, people simply add it manually to the .go file. For example, adding the github.com/gorilla/mux into the import by typing the below line manually at the .go file:

import "github.com/gorilla/mux"

After adding this line, people usually run go mod tidy , and this command will update both go.mod and go.sum files, adding missing dependencies and removing unused ones. Hence, at your go.mod file, you will now see:

require github.com/gorilla/mux v1.8.0

P.S. Why do we manually write import "github.com/gorilla/mux"instead of letting the IDE detect and import it? Because most IDEs only recognise Go standard libraries (which is located at $GOROOT/src. for example, my fmt is located at /opt/homebrew/Cellar/go/1.19/libexec/src/fmt) and will automatically imports them to the .go file. For example, for standard libraryfmt , you just need to write a function that uses fmt.Println(), then the IDE will automatically put (== automatically import)import "fmt"in the .go file the function is used. However, for non-standard libraries, we would need to write the import ourselves.

go get — If you just want to update a dependency, rather than traversing through the whole dependency trees to clean it up using go mod tidy, you can run go get to get the specific dependency that you want. e.g.

go get -u github.com/gorilla/mux

This will add a line at go.mod:

require github.com/gorilla/mux v1.8.0 // indirect

In the old days, before go module were there, before you can use go mod tidy , go get is also a way to download different versions of a package. However, nowadays, to be honest, add the package name with different version to the import ()block of the .go files and run go mod tidy will do the same thing. Hence, I could imagine that there will be decreasing usage in go get .

go install — If you want to update a binary, but you don’t want that to mess up / change your go.mod file, then you better run go install ! For example, for updatinggopls package (Go’s official language server), you definitely don’t want it to appear in your go.mod file.

go mod download — When you first clone a new project, or using a docker. file, you can run/write this command right away, to download dependencies to module cache. This command seems to be a product of the issue that go mod vendor did not download the packages correctly. It was created in 2018 to fix the issue above for Go v1.11. However, nowadays,go mod tidy will do the same thing. Hence, basically, there is not really need to run this command.

History

Go modules are introduced in Go 1.11 in 2018, together with a variable called GO111MODULE . This article from Mael illustrates the history quit well.

In short, there are two ways to deal with modules: the (1) Module-Aware mode, or the (2) GOPATH mode. After Go 1.16, (1) is enabled by default.
The go get is a product from the history — the (2) GOPATH mode. The two commands ( go mod downloadand go mod tidy) which withmod (stands for module) in their compositions are the newer (1) Module-Aware mode. What about go install ? It is a nice substitution of the annoying go get , since go get always update the go.mod files but sometimes developers just want to update the binaries without changing the project’s go.mod files. Now, we can use go install to achieve this.

Example of using `go mod tidy` & `go get`

When you are at a blank project/directory, and run:

go mod init shelly.com/packages

You will create a file named go.sum with the following content:

module shelly.com/packagesgo 1.19

Now, write a line which uses the fmt package like below:

package mainfunc main() {
greeting := fmt.Sprintf("Hello, %s", "James") // write this line
}

You will notice that your IDE, be it GoLand or Visual Studio Code, will automatically add import "fmt" to your file. Exactly as below:

package main
import "fmt" // this line will appear automatically
func main() {
greeting := fmt.Sprintf("Hello, %s", "James")
}

Now, add "github.com/gorilla/mux"at main.go like below:

package mainimport (
"fmt"
"github.com/gorilla/mux" // add this line
)
func main() {
greeting := fmt.Sprintf("Hello, %s", "James")
fmt.Println(greeting)
}

Now run go mod tidy . This will:

  1. create go.sum file with the following content:
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=

2. add require github.com/gorilla/mux v1.8.0 at go.mod file

module shelly.com/packagesgo 1.19require github.com/gorilla/mux v1.8.0

Now run go get github.com/go-chi/chi@master. This will add the below 2 lines to go.modfile:

require github.com/gorilla/mux v1.8.0require github.com/go-chi/chi v1.5.4 // indirect

Plus, adding these lines to go.sum:

github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=

Note that //indirect is written after the package because we haven’t import gorilla/mux package anywhere (i.e. we do not have import "github.com/gorilla/mux"written anywhere at any .go files).

If we now run go mod tidy , then the line with //indirectwill be deleted.

Sometimes, the //indirect would not be deleted, if the package is used by your direct dependencies.

Any indirect dependency which is not listed in the go.mod file of your direct dependency or if direct dependency doesn’t have a go.mod file, then that dependency will be added to the go.mod file with //indirect as the suffix. We will see an example of this later in the article to know this better.
ref: https://golangbyexample.com/go-mod-sum-module/

Hence, it is generally recommended to run go mod tidybefore any commit and release.

Miscellaneous

There are also other go commands, such as go build& go test . Notice that these 2 commands no longer modify go.mod & go.sum by default.

go mod tidy are so versatile, and can even be used when upgrading the Go version. When upgrading Go version on existing project, you just need to do the following:

  1. update go.mod file manually (e.g. change the wording go 1.18 to go 1.19 )
  2. run go mod tidy

done!

Wohoo…that was a long article. How do you feel so far?
Furthermore, what is your understanding about these 3 confusing Go commands? Do you have other opinions than me?

Please leave some comments. Discussions are always enlightening! :)

Thanks for reading till here. If you found the article helpful, feel free to clap multiple times on the article (one person can clap up to 50 times!), or ❤️ give me some tips following the below link ❤️. Thank you in advance :)

You are also welcome to clap for this article through liker land, so I can receive some coins on the blockchain! :)

--

--