Go Packages and Modules
In this tutorial we are going to discuss about Go packages and modules. Packages are the most powerful part of the Go language. In the most basic terms, A package is nothing but a directory inside your Go workspace containing one or more Go source files, or other Go packages.
The package is a way of code reusability in GO. As the name suggests, it is a way of grouping related code. Go modules is a way of dealing with dependencies in golang.
Every GO source file (.go file) in a GO application file belongs to a package. That is why every .go file starts with.
The above package declaration must be the first line of code in your Go source file. All the functions, types, and variables defined in your Go source file become part of the declared package.
There are 2 types of packages available in Golang.
The only main is the executable package in GoLang. A .go file might belong to the main package present within a specific directory. We will see later how the directory name or the .go file name matters. The main package will contain a main function that denotes the start of a program. On installing the main package, it will create an executable in the $GOBIN directory.
Any package other than the main package is a utility package or reusable package. It is not self-executable. It just contains the utility function and other utility things that an executable package can utilize.
Modules are golang support dependency management. A module, by definition, is a collection of related packages with go.mod at its root. The go.mod file defines the
- Module import path.
- Dependency requirements of the module for a successful build. It defines both project’s dependencies requirements and also locks them to their correct version.
Consider a module as a directory containing a collection of packages. The packages can be nested as well. Modules provide
- Dependency Management
- With modules, go project doesn’t necessarily have to lie in the $GOPATH/src folder.
In addition to go.mod file, go also keeps a go.sum file, which contains the cryptographic hash of bits of all project’s dependent modules. This to make validate that your project’s dependent modules are not changed.
Modules were introduced in go in version 1.11. Let’s see version wise changes to fully understand what was the limitations earlier and what has changed since modules
- Pre Go version 1.11 – Modules did not exist at all
- Go Version 1.11 – Modules was introduced but not finalized
- Go Version 1.13 – Modules was introduced
Pre Go version 1.11
Before modules go only had packages. $GOPATH location would have three directories
Following are the problems which existed before the modules eraAny GO project has to be inside the $GOPATH/src directory
1. All the dependency will be downloaded in the $GOPATH/src
This was a big limitation in terms of that it restricted where you can keep your project.
2. No native dependency management support
Also, one issue before modules was that there was no way to specify a dependency in a project. Alternate solutions such as dep, glide were available, but a native solution was missing.
3. All the dependency will be downloaded in the $GOPATH/src directory without versioning
When we do a go get it will download the required package in the $GOPATH/src directory. So before go version 1.11, below go get command
go get github.com/reugn/go-quartz
It will download the package at the location
Notice one thing about the go get command above that no version was specified. Hence it downloads the latest version present.
Also, notice the downloaded package. Even it doesn’t list down any versioning info. Now, this is a problem.
What if there is an update in the github.com/reugn/go-quartz package and you want to get that update. Since there is no versioning the updated package will get downloaded at the same location replacing the older one.
In Go version 1.11
In Go 1.11. modules were introduced but not finalized. So if you still using it then better to switch to the latest version
After Go version 1.13
We already discussed all the problems which existed before the pre-modules era. Now let’s see how each of these problems got resolved with the introduction of modules.
The first problem was
All Go project in $GOPATH/src directory
With modules, this is no longer a requirement.
No native dependency management support
Modules introduced native dependency management within go. With modules, it provides two new files which are
With go.mod and go.sum files we are able to install a precise version of a dependency without breaking anything. We already gave a brief introduction to these files at the beginning of this tutorial. Later in the tutorial, we will look at it in detail
All the dependency will be downloaded in the $GOPATH/pkg/mod directory with versioning
So if you download a different version of the same library then both will be downloaded in a different directory inside $GOPATH/pkg/mod without overriding each other. $GOPATH/pkg/mod will have two things inside it
- cache – This is the folder where all dependencies will get downloaded along with the zipped code
- Zipped code of all downloaded dependencies will get copied over from the cache directory.
Also, there is a new env introduced named GO111MODULE
When GO111MODULE=off, then go get will behave in the old way where it will download the dependency in the $GOPATH/src folder.
When GO111MODULE=on, then go get will behave in a new way, and all the modules will get downloaded in the $GOPATH/pkg/mod/cache folder with versioning.
When GO111MODULE=auto, then
- When running go get outside the $GOPATH/src folder, then will behave as if it is GO111MODULE=on
- When running go get inside the $GOPATH/src folder, then will behave as if it is GO111MODULE=off