We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

Go Packages vs Modules

Lane Wagner
Lane WagnerBoot.dev co-founder and backend engineer

Last published

Table of Contents

Packages, modules, and repositories organize Go code at different levels. A package is a directory of code that's compiled together, a module is a collection of packages released together, and a repository can contain one or more modules.

All the content from our Boot.dev courses are available for free here on the blog. This one is the "Packages and Modules" chapter of Learn Go. If you want to try the far more immersive version of the course, do check it out!

How Go Code Is Organized

Go programs are organized into packages. A package is a directory of Go code that's all compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package (directory).

A repository contains one or more modules. A module is a collection of Go packages that are released together.

To recap how packages and modules work in your project directory structure:

  • You will have many git repositories on your machine, typically one per project.
  • Each repository is typically a single module.
  • Each module contains one or more packages.
  • Each package consists of one or more Go source files in a single directory.

Packages

Every Go program is made up of packages.

A package named main has an entry point at the main() function. A main package is compiled into an executable program.

A package by any other name is a "library package". Libraries have no entry point. Libraries simply export functionality that can be used by other packages. For example:

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	fmt.Println("My favorite number is", rand.Intn(10))
}

This program is an executable. It is a main package and imports from the fmt and math/rand library packages.

Package Naming

By convention, a package's name is the same as the last element of its import path. For instance, the math/rand package comprises files that begin with:

package rand

That said, package names aren't required to match their import path. For example, I could write a new package with the path github.com/textio/rand and name the package random:

package random

While the above is possible, it is discouraged for the sake of consistency.

One Package Per Directory

A directory of Go code can have at most one package. All .go files in a single directory must all belong to the same package. If they don't, an error will be thrown by the compiler. This is true for main and library packages alike.

Modules

A file named go.mod at the root of a project declares the module. It contains:

  • The module path
  • The version of the Go language your project requires
  • Optionally, any external package dependencies your project has

The module path is just the import path prefix for all packages within the module. Here's an example of a go.mod file:

module github.com/bootdotdev/exampleproject

go 1.26.0

require github.com/google/examplepackage v1.3.0

Each module's path not only serves as an import path prefix for the packages within but also indicates where the go command should look to download it. For example, to download the module golang.org/x/tools, the go command would consult the repository located at https://golang.org/x/tools.

An "import path" is a string used to import a package. A package's import path is its module path joined with its subdirectory within the module. For example, the module github.com/google/go-cmp contains a package in the directory cmp/. That package's import path is github.com/google/go-cmp/cmp. Packages in the standard library do not have a module path prefix.

-- Paraphrased from Golang.org's code organization

You Don't Need to Publish Your Code

You don't need to publish your code to a remote repository before you can build it. A module can be defined locally without belonging to a remote repository. However, it's a good habit to keep a copy of all your projects on some remote server, like GitHub.

A Note About GOPATH

The $GOPATH environment variable has a default value somewhere on your machine, typically in the home directory at ~/go. In the newer Go modules setup, you don't need to worry about that.

These days you should avoid storing your projects in $GOPATH. That's the old way of doing things and can cause unexpected issues, so better to just avoid it. You can put your code wherever you want.

Frequently Asked Questions

What is the difference between a Go package and a module?

A package is a directory of Go code that is compiled together. A module is a collection of Go packages that are released together.

What is the difference between a main package and a library package?

A main package has an entry point at main() and compiles into an executable program. A library package has no entry point and exports functionality for other packages to use.

Can one directory contain multiple Go packages?

Go source files compiled together from one directory must belong to the same package. Otherwise, the compiler reports an error.

Does a Go package name have to match its directory?

No. By convention, a package name matches the last element of its import path, but Go does not require it. Using a different name is discouraged for consistency.

Is GOPATH still required with Go modules?

No. When using Go modules, you should avoid storing projects in GOPATH and can put your code wherever you want.