Go

What are module graph pruning and lazy module loading (Go 1.17), and why did go.mod files get so much longer?

Question 440HardGo 1.22 to 1.25

Before 1.17 the go command had to load the go.mod of every module in the transitive graph, including modules that provide no package you actually build. From go 1.17 onward two changes apply:

  • Complete requirements: the main module's go.mod explicitly lists every module that provides a package imported (transitively) by the main module's packages or tests. That is why a second require block full of // indirect entries appears.
  • Pruning: for a dependency whose go.mod says go 1.17 or higher, only its direct requirements enter your module graph. Its dependencies' own requirements are pruned out, because that module's go.mod is already complete for its own packages.
  • Lazy loading: since the main go.mod is complete, the go command can often build without reading (or downloading) the go.mod files of pruned modules at all.
require (
    github.com/google/uuid v1.6.0
    golang.org/x/sync v0.8.0
)

require (   // added automatically by go mod tidy, go 1.17+
    github.com/davecgh/go-spew v1.1.1 // indirect
    golang.org/x/sys v0.25.0 // indirect
)

go mod tidy -go=1.17           # upgrade an old module to pruned graphs
go mod tidy -compat=1.16       # keep extra go.sum entries for older toolchains

Consequences: smaller effective graphs, fewer downloads, and fewer irrelevant go.sum lines. Dependencies with a go line below 1.17 are not pruned, so their full transitive requirements still count. A module's own go line therefore changes how other modules see its requirements. Interviewers look for "indirect entries are there on purpose, so don't delete them by hand: run go mod tidy".

More on Modules, Packages & Tooling

All 36 Modules, Packages & Tooling questions