← O-Reilly Learning Go

Modules, Packages and Imports

modulespackagesimports#Golang

Overview

Library management in Go is based on around three concepts.

  1. repository
  2. module
  3. package

Repository : A place in a version control system where the source code for the project is stored
Module: A bundle of Go source code that is distributed and versioned as a single unit. Modules are stored in repository
Package: Modules consist of one or more packages, which are directories of source code. Packages give a module organization and structure.

Note: While you can store more than one module in a repository, it is discouraged. Everything within a module is versioned together. Maintaining two modules in one repository requires you to track separate versions for two different modules in a single repository.

Go modules follow the semantic import versioning rule.
This rule has two parts:
• The major version of the module must be incremented.
• For all major versions besides 0 and 1, the path to the module must end in vN, where N is the major version.
example : "github.com/learning-go-book-2e/simpletax/v2"

The require directive

The first require section list the direct dependencies of the module.
The second require section list the dependencies of the dependencies of the module. We can see // indirect at the end of each dependency.

Override a package name

We can simply override a package name like this newname package_path if there is a same package name. We can also use two other symbols . and _.
. (dot) places all the exported identifiers in the imported package into the current package’s namespace; you don’t need a prefix to refer to them.
This is discouraged because it makes your source code less clear. You can no longer tell whether something is defined in the current package or whether it was imported by simply looking at its name.

Blank import (_)
Imports a package only to run its init() functions (side effects), without giving you a usable name. You can't call anything from it. Common use: registering a database driver, e.g. import _ "github.com/lib/pq".
(Contrast: import f "fmt" is a named alias — you rename the package and call it as f.Println(). The _ form is the opposite: no name, no calls, side effects only.)

Internal Package

We can use package name internal to hide packages from the external consumers. Use any other name and it is fully public.
When you create a package called internal, the exported identifiers in that package and its subpackages are accessible only to the direct parent package of internal and the sibling packages of internal.

Organizing Go module

Intended for application

The module is intended to be used only as an application, make the root of the project the main package. The code in the main package should be minimal; place all your logic in an internal directory, and the code in the main function will simply invoke code within internal. This way, you can ensure that no one is going to create a module that depends on your application’s implementation.

Intended for library

If the module to be used as a library, the root of your module should have a package name that matches the repository name. This makes sure that the import name matches the package name. To make this work, you must ensure that your repository name is a valid Go identifier.
If the library includes some utilities, we put each one in its own directory under cmd/ (e.g. cmd/toolname/), each with its own main function, so it builds into a separate binary.

Overriding the dependencies

replace github.com/jonbodner/proteus => github.com/someone/my_proteus v1.0.0  A replace directive redirects all references to a module across all your module’s dependencies and replaces them with the specified fork of the module.

exclude github.com/jonbodner/proteus v0.10.1Go provides the exclude directive
to prevent a specific version of a module from being used.

Retracting

retract = "this published version of my module is bad, don't automatically use it," declared in go.mod and shipped in a later release.

module github.com/you/mymodule

go 1.22

retract v1.2.0              // single bad version
retract [v1.3.0, v1.3.5]    // a range, inclusive
retract (                   // multiple, grouped
    v1.4.0
    v1.4.1
)

Workspaces

Go workspaces solve the problem of testing local changes across multiple unpublished modules without editing any go.mod files. You define a go.work file above your modules, listing their local paths with use. When one module imports another that's listed in go.work, Go resolves it from the local filesystem instead of the module cache, regardless of the version in go.mod. Key commands are go work init, go work use, go work edit, and go work sync (syncs version requirements back into each module's go.mod). Unlike a replace directive, go.work isn't committed to the repo — it's local dev state, usually gitignored. So there's no risk of forgetting to remove it before a release. It only affects local builds/tests run within the workspace; it has no effect on the published modules themselves.

Module Proxy Server

Go libraries live on source repos like GitHub and GitLab, but they're not downloaded directly from there. Requests go through a proxy server run by Google. When a user requests a certain library version, the request hits the proxy, which checks if that version was previously requested. If yes, it serves the cached copy. If not, it fetches the package from the source, caches it, then returns it to the user. Separately, there's a checksum database that records a hash for every module version ever published. The first time you fetch a version, its hash gets saved to your go.sum. This guarantees immutability — once a version's hash is recorded, that exact version can never silently change content again. If it ever does, the hash mismatch fails the build, which is what protects against tampering.

Libraries can also be hosted on private repositories. In that case, we need to set environment variables so Go fetches directly from the source instead of going through the public proxy and checksum database.
Some env variables to setup:

  • GOPRIVATE
  • GOSUMDB
  • GONOSUMCHECK
  • GOPROXY
    and so on.