Modules and Packages
Packages
Section titled “Packages”Every Go file belongs to a package, declared at the top of the file. A directory contains one Package. Executables use package main; libraries use any other name.
myproject/ main.go // package main internal/ db/ db.go // package db auth/ auth.go // package auth pkg/ utils/ utils.go // package utilsPackage Naming Conventions
Section titled “Package Naming Conventions”- Lowercase, single word:
http``json``strings - No underscores or mixed case
- The directory name matches the package name
- Avoid repetition:
pkg/utils/utils.go-> the package isutilsNotutilsutils
Import Paths
Section titled “Import Paths”The import path is the module path plus the directory path:
import ( "github.com/you/myproject/internal/db" "github.com/you/myproject/pkg/utils")Internal Package
Section titled “Internal Package”Packages under a directory named internal cannot be imported by code outside the module tree Rooted at the parent of internal:
myproject/ internal/ secret/ // importable by myproject/* only external/ public.go // importable by anyoneThis is enforced by the Go toolchain, not just a convention.
go.mod
Section titled “go.mod”The go.mod file declares the module path and dependency requirements:
module github.com/you/myproject
go 1.22
require ( github.com/go-chi/chi/v5 v5.0.12 github.com/lib/pq v1.10.9)
require ( github.com/go-sql-driver/mysql v1.7.1 // indirect)Fields:
module: the module path (used as the import prefix for all packages in the module)go: the minimum Go version requiredrequire: direct dependencies (with versions)indirect: transitive dependencies not directly imported by any package
Semantic Versioning
Section titled “Semantic Versioning”Go modules use semantic versioning: MAJOR.MINOR.PATCH.
v1.2.3: MAJOR=1, MINOR=2, PATCH=3v0.x.y: pre-release — no compatibility guaranteev1.x.y: stable — backward compatibility within v1v2.0.0and beyond: must use a different module path with/v2suffix
Major Version Bumping
Section titled “Major Version Bumping”For v2+, the module path must include the major version:
// v1module github.com/you/myproject
// v2 (must update module path and all import paths)module github.com/you/myproject/v2Importing a v2+ module:
import "github.com/you/myproject/v2"The /v2 suffix is part of the module path, not the package path. This allows v1 and v2 to coexist In the same dependency graph.
go.sum
Section titled “go.sum”The go.sum file records the cryptographic hashes (SHA-256) of every module version used. It Ensures reproducible builds:
github.com/go-chi/chi/v5 v5.0.12 h1:exqT1FsjFNFK...github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznF/...Each module version has two entries: one for the .zip and one for go.mod. Always commit go.sum Alongside go.mod.
Dependency Management Commands
Section titled “Dependency Management Commands”go mod init github.com/you/myproject # initialize a new modulego mod tidy # add missing deps, remove unused depsgo mod download # download modules to module cachego mod verify # verify checksums against go.sumgo mod graph # print dependency graphgo mod why github.com/pkg/dep # explain why a dependency is neededgo list -m all # list all dependencies (direct + indirect)go list -m -versions github.com/go-chi/chi/v5 # list available versionsAdding a Dependency
Section titled “Adding a Dependency”go get github.com/go-chi/chi/v5@v5.0.12 # add specific versiongo get github.com/go-chi/chi/v5 # add latest versiongo get github.com/go-chi/chi/v5@latest # update to latestUpdating Dependencies
Section titled “Updating Dependencies”go get -u ./... # update all dependencies to latest minor/patchgo get -u=patch ./... # update all dependencies to latest patch onlyRemoving a Dependency
Section titled “Removing a Dependency”go mod tidy # removes unused dependencies automaticallyThe Module Cache
Section titled “The Module Cache”Downloaded modules are stored in $GOPATH/pkg/mod/. The cache is read-only and content-addressed (by version). Multiple projects share the same cache.
Clear the cache:
go clean -modcacheMinimal Version Selection (MVS)
Section titled “Minimal Version Selection (MVS)”Go uses Minimal Version Selection, not SemVer resolution. For each dependency, Go selects the Maximum version required by any module in the graph. It does not upgrade transitive dependencies to Their latest version.
Example: if A requires C@v1.1.0 and B requires C@v1.2.0, Go uses C@v1.2.0 (the maximum required Version). It does not use C@v1.3.0 even if that exists, because no module requires it.
MVS ensures reproducible builds: the same go.mod always produces the same dependency set.
go.work (Workspace Mode)
Section titled “go.work (Workspace Mode)”Go 1.18+ supports workspaces for multi-module development:
go 1.22
use ( ./backend ./frontend ./shared)Workspace mode allows editing multiple modules simultaneously without publishing. go build go testAnd go run use the local modules in the workspace instead of the module cache.
go work init ./backend ./frontend ./sharedgo work use ./new-module # add a module to the workspacego work sync # sync go.mod files with workspacego.work should not be committed to the repository (add to .gitignore). It is a local development Convenience.
Replacing Dependencies
Section titled “Replacing Dependencies”The replace directive in go.mod substitutes a module with a local path or a different version:
module github.com/you/myproject
go 1.22
require github.com/you/dependency v1.0.0
replace github.com/you/dependency => ../dependencyUse cases:
- Local development with an unreleased dependency
- Forking and patching a dependency
- Debugging with a local copy
replace can also point to a different version or a fork:
replace github.com/orig/pkg => github.com/fork/pkg v1.2.3Vendor Directory
Section titled “Vendor Directory”go mod vendor copies dependencies into a vendor/ directory. The build then uses the vendored Copies instead of the module cache:
go mod vendorgo build -mod=vendor # build using vendor directoryVendoring is optional and primarily used in environments without network access (air-gapped builds, CI with restricted internet).
Intuition
Section titled “Intuition”Modules are neighborhoods, packages are houses: A Go module is a versioned neighborhood with a map (go.mod) listing which other neighborhoods it connects to. Packages within a module are individual houses — each with one entrance (the directory name). The go.sum file is the neighborhood watch ledger, recording exactly which version of every neighbor’s house you’re using, so nobody can swap in a different house overnight.
Why it matters: Go’s module system gives you reproducible builds without a central registry. Minimal Version Selection (MVS) means go.mod always resolves to the same dependencies — no “works on my machine” surprises from floating versions.
The key insight: MVS is deliberately conservative — it picks the minimum version that satisfies all constraints, not the latest version, making builds predictable and go.mod diffs meaningful.
Common Pitfalls
Section titled “Common Pitfalls”Not running
go mod tidyafter changes. After adding or removing imports, always rungo mod tidyto keepgo.modandgo.sumsynchronized.V2+ without
/v2suffix. If you release v2 of a module without updating the module path to include/v2Go treats it as v1 and the version number is ignored.Committing
go.work. The workspace file is a local development tool. Commit it only for monorepo setups where it is part of the intended workflow.Overusing
replace.replacedirectives in committedgo.modfiles break builds for other developers. Use them only for local development or ingo.work.Ignoring indirect dependencies.
go mod tidymanages indirect dependencies. Manually editing them risks build inconsistencies.Large
go.sumfiles. This is normal for projects with many dependencies. Do not try to minimize it manually.Forgetting
go.work sync. After adding modules to a workspace, rungo work syncto updatego.modfiles with workspace-relevant information.
Summary
Section titled “Summary”This topic covers the core concepts of modules and packages, including underlying theory, practical implementation, and key applications.
Key concepts include:
- core concepts and terminology
- algorithms and computational thinking
- practical implementation
- security and ethical considerations
- applications in the real world
Understanding these concepts thoroughly is essential for both examinations and practical programming, and requires both theoretical knowledge and hands-on practice.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.