๐Ÿ“ฆGo Modules & PackagesLESSON

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

DirectiveMeaning
moduleModule path (import prefix)
goMinimum Go toolchain version
requireDirect 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, not math_util)
  • One package per directory (except _test packages)
  • The main package 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?