What is a Go package?
A Go package is a collection of Go source files in the same directory that are compiled together. It can contain functions, types, and variables. Go packages organize code and provide a way to share code between different program parts.
By convention, the package name is the same as the last element of the import path. For example, the package name for
the fmt
package in the fmt
directory is fmt
. You can name the package differently from the directory name, but it
is not recommended.
When a Go application is compiled, the Go compiler compiles all the packages imported by the main package. The main
package contains the main
function and is the entry point of the program. However, all the imported packages can be
compiled separately as well, even if they do not contain the main
function. That’s what happens when we run unit tests
for all packages in a Go project — each package is compiled separately and can be tested independently.
The directory structure does not have to match the package dependencies. For example, given the following directory structure:
service/
service.go
api/
api.go
db/
db.go
The packages service
, api
, and db
can be completely independent. The service
package does not include the
api.go
and db.go
files because they are in a different directory. Go’s package dependency graph has no relation to
the directory structure.
What is a Go module?
A Go module, introduced in Go 1.11, is a collection of Go packages that are versioned
together. A Go module is defined by a go.mod
file located at the module’s root. The go.mod
file contains the module
name and the versions of the dependencies the module uses.
A Go module can contain multiple packages, and the packages do not need to be related to each other.
A Go module can exist at any level of the directory structure, even nested within another module. The Go toolchain treats all Go modules as independent entities, regardless of their location in the directory structure.
How to use multiple modules in one Go workarea
1. Create a new Go workarea:
mkdir -p go-modules
cd go-modules
go mod init example.com/go-modules
2. Create a simple Go file in the root of the workarea:
package main
import "fmt"
func main() {
fmt.Printf("Hello, world.\n")
}
3. Create a new Go module in a subdirectory:
mkdir -p adder
cd adder
go mod init example.com/go-modules/adder
With the following Go file in the adder
directory:
package adder
func Add(a, b int) int {
return a + b
}
4. Use the adder
package in the main
package:
You cannot simply import the adder
package in the main
package because they are in different modules.
One way to use the adder
package is to publish it and use go get
to download it as the main
dependency. However,
this is impractical for local development and doesn’t make sense when we explicitly want to use multiple modules in one
repository.
The proper way is to use a workspace, declared in the go.work file, introduced in Go 1.18.
In the top level of the workarea, create a go.work
file with all the modules in the subdirectories:
go work use -r .
The resulting go.work
file will look like this:
go 1.23.2
use (
.
./adder
)
Now, you can import the adder
package in the main
package:
package main
import (
"fmt"
"example.com/go-modules/adder"
)
func main() {
fmt.Printf("Hello, world.\n")
fmt.Print(myadder.Add(1, 2))
}
Should I use multiple Go modules in one repository?
Generally, it is not recommended to use multiple Go modules in one repository. However, there are some cases where it makes sense, like:
- Temporarily pull in a third-party module to add a feature before this feature is merged upstream.
- Work on multiple interdependent modules that can be versioned and released independently.
Usually, it is better to use packages within a single module to organize and decouple code.
Further reading
- Recently, we wrote about using the staticcheck linter on a large Go project.
- Previously, we described how to use Go to unmarshal JSON null, set, and missing fields.
- We also published an article on accurately measuring the execution time of Go tests.
Multiple modules in one Go project on GitHub
Example Go project with multiple modules
Watch an explanation of Go modules and packages, along with an example of using multiple modules in one repository
Note: If you want to comment on this article, please do so on the YouTube video.