Go Modules & Packages
Why modules replaced GOPATH
Before Go 1.11, all Go code had to live under a single GOPATH directory. This made it impossible to have two projects depending on different versions of the same library. Go modules (introduced in Go 1.11, made default in 1.16) solve this: each project is a self-contained module with an explicit dependency manifest.
go mod init
Create a new module with:
The argument is the module path โ the canonical import prefix for all packages in this module. By convention it matches the repository URL so tools can fetch it automatically.
go.mod anatomy
| Directive | Meaning |
|---|---|
module | Module path (import prefix) |
go | Minimum Go toolchain version |
require | Direct dependencies and their versions |
go.sum
go.sum stores cryptographic hashes of every dependency (direct and transitive). The toolchain refuses to use a dependency whose hash doesn't match โ this prevents supply-chain attacks.
Always commit both go.mod and go.sum. Never hand-edit go.sum.
Managing dependencies
Run go mod tidy before every commit to keep go.mod and go.sum accurate.
Package naming rules
- Directory name = package name (they must match)
- Package names: lowercase, no underscores (e.g.
mathutil, notmath_util) - One package per directory (except
_testpackages) - The
mainpackage is special โ it's the entry point for an executable
Import the sub-package using the full module-relative path:
Exported vs unexported
Capitalisation controls visibility across packages:
This is Go's entire access-control system. There are no public/private keywords.
internal/ packages
Placing a package under an internal/ directory restricts who can import it:
External modules (other people's code) cannot import anything under your internal/. Use this to expose a stable public API while hiding implementation details.
Avoiding import cycles
Go packages must form a directed acyclic graph (DAG) โ circular imports are a compile error.
The fix is to extract shared types into a third package that neither a nor b imports from each other:
A types or model package containing only plain structs and interfaces โ no logic โ is the standard pattern for breaking cycles.
Knowledge Check
What does `go mod tidy` do?
Why would you place a package under an `internal/` directory?
What makes an identifier exported in Go?