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
requireblock full of// indirectentries appears. - Pruning: for a dependency whose go.mod says
go 1.17or 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
- Q438What is Profile-Guided Optimization (PGO) in Go and how do you use it in production?
- Q439How does Go ship behavior changes without breaking old code? Explain GODEBUG, the godebug directive and //go:debug. What does this print?
- Q441Explain the build cache, the module cache and test result caching. When does go test print "(cached)" and how do you defeat it?
- Q442What is //go:linkname, and what changed about it in Go 1.23?