Why there are two “require” blocks in go.mod since Go 1.17?

Because in Go 1.17 the module graph has been changed to enable pruning and lazy loading. The second require block contains indirect dependencies.

https://golang.org/doc/go1.17#go-command

If a module specifies go 1.17 or higher, the module graph includes only the immediate dependencies of other go 1.17 modules, not their full transitive dependencies. […]

[…] If a module specifies go 1.17 or higher in its go.mod file, its go.mod file now contains an explicit require directive for every module that provides a transitively-imported package. (In previous versions, the go.mod file typically only included explicit requirements for directly-imported packages.)

Because the number of explicit requirements may be substantially larger in an expanded Go 1.17 go.mod file, the newly-added requirements on indirect dependencies in a go 1.17 module are maintained in a separate require block from the block containing direct dependencies.

Note: the go.mod file that you posted in your question has //indirect dependencies in the first require block. I suspect, based on the wording “newly-added” in the quoted docs, that this is because those //indirect dependencies were already listed there and go mod tidy doesn’t rearrange them. If you:

  • manually delete one of those
  • and/or recreate the go.mod file with Go version set to 1.17 or higher
  • and/or run go mod tidy -go=1.17

then it will separate direct and //indirect dependencies in the two blocks. Anyway, this is a visual convenience, the documentation doesn’t mandate creation of two separate blocks.


Additional references:

  • graph pruning: https://go.dev/ref/mod#graph-pruning

  • behaviors dependent on go.mod‘s go directive: https://go.dev/ref/mod#go-mod-file-go

Leave a Comment