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.

Basic Structure

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?

  1. Clarity: Developers can quickly see which dependencies they directly control
  2. Review efficiency: In code reviews, changes to direct vs indirect deps have different significance
  3. 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.

Try It — go.mod Formatter

Open full tool