Packages, modules and tooling · 3 MIN READ

A module is a release boundary; a package is a directory

Resolve module roots, import paths, internal visibility and major-version suffixes.

A repository, a module and a package can be three different boundaries. Trace the module path plus the package subdirectory before changing imports. A version suffix is part of the import identity; a folder name alone does not decide which source the compiler builds.

Packages and production tooling · A MAP OF THE IDEA

  1. Repository
  2. go.mod root
  3. Package import
  4. Versioned API

Useful when

  • Resolve module roots, import paths, internal visibility and major-version suffixes.

Watch out

  • A module versions a set of packages together. A package groups source in one directory; the repository name does not override its declared package identifier.

Implementation & operation cost: Each extra module adds versioning, publishing and consumer-compatibility work; package boundaries inside one module are cheaper.

01

Locate the source that is actually selected

Start from the working directory and inspect the active module and workspace. A nested go.mod starts another module and can make ./... skip source you expected to test. Package names need not match the final path element, although a clear correspondence usually makes code easier to read.

bash
go env GOMOD GOWORK
go list -f '{{.ImportPath}} => {{.Dir}}' ./...
go list -m
Read the code

GOMOD identifies the active module file. The package listing maps each import to a real directory, so an unexpected checkout or nested module becomes visible before you edit source.

02

Major versions have distinct identities

For ordinary module-aware releases at v2 and above, /v2 is part of the module and import path. Updating a version number without updating the path is not a compatible major upgrade. Some legacy modules use +incompatible; do not copy that exception into a new module design.

text
module example.com/catalog/v2

go 1.24.0
Read the code

The root package is imported as example.com/catalog/v2; a subpackage is example.com/catalog/v2/search. The file illustrates path structure rather than asking you to fetch a nonexistent example module.

03

Keep ownership inside one dependency direction

An internal directory limits which importers may reach a package; it is not an authorization boundary for running code. A package import cycle fails before the program starts. Move a small consumer-owned contract or shared value to an acyclic boundary instead of solving a cycle with init side effects.

TAKE THIS WITH YOU

Identify the active module and actual package directory first. Treat a new major import path as an API migration, and keep the dependency graph acyclic.

Check your understanding

How do a module and a package relate?

Go to the source

Progress stays in this browser. No account needed.