Multiple Require Blocks in go.mod
Learn why go.mod files have multiple require blocks and how Go separates direct from indirect dependencies. Understand how go mod tidy organizes require statements.
Detailed Explanation
Multiple Require Blocks
A go.mod file typically contains two separate require blocks: one for direct dependencies and one for indirect dependencies. This separation is a convention maintained by go mod tidy.
Direct Dependencies Block
require (
github.com/gin-gonic/gin v1.9.1
github.com/spf13/cobra v1.8.0
google.golang.org/grpc v1.60.1
)
These are packages that your source code imports directly. They appear without the // indirect comment.
Indirect Dependencies Block
require (
github.com/bytedance/sonic v1.10.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
golang.org/x/net v0.19.0 // indirect
)
These are transitive dependencies — packages required by your direct dependencies. Go marks them with // indirect.
Why Separate Blocks?
- Clarity: Developers can quickly see which dependencies they directly control
- Review efficiency: In code reviews, changes to direct vs indirect deps have different significance
- Maintenance: Direct deps are what you explicitly chose; indirect deps are managed by
go mod tidy
When Indirect Becomes Direct
An indirect dependency becomes direct when you import one of its packages in your code. Running go mod tidy will move it to the direct block and remove the // indirect comment.
Manual Edits vs go mod tidy
While you can manually edit go.mod, running go mod tidy afterwards will:
- Add missing dependencies
- Remove unused dependencies
- Reorganize require blocks
- Fix the direct/indirect classification
Formatting Conventions
- Each block is sorted alphabetically by module path
- Version numbers are aligned with spaces
- Indentation uses tabs
- The formatter produces this canonical format automatically
Use Case
Understanding multiple require blocks is essential when reviewing dependency changes in pull requests. When a teammate adds a new library, you will see changes in both the direct block (the new dependency) and the indirect block (its transitive dependencies). A go.mod formatter helps maintain clean separation and consistent formatting across the team.