go get vs go mod download: Key Differences in Go Module Management

The fundamental difference between go get and go mod download is that go get modifies dependency metadata in go.mod and go.sum to add, upgrade, or remove requirements, while go mod download only populates the local module cache without altering module definitions.

When working with Go modules in the golang/go source tree, distinguishing between these commands is critical for effective dependency workflow. While both commands interact with the module ecosystem, they serve different architectural purposes—one managing metadata mutations in src/cmd/go/internal/modget/get.go and the other managing artifact caching in src/cmd/go/internal/modcmd/download.go.

The Dependency Management Role of go get

The go get command serves as the primary dependency management tool. According to the source implementation in src/cmd/go/internal/modget/get.go, the runGet function orchestrates a complete resolution and mutation cycle for your module's requirements.

Metadata Mutation and Resolution Logic

When you execute go get, the command performs a full module resolution walk that handles wildcards, pattern queries, and version upgrades. The resolver logic in runGet (particularly around lines 31-71) repeatedly applies queries, processes upgrades, and manages wildcard handling to determine the final dependency graph.

After resolving the requested changes, go get invokes modload.WriteGoMod to persist modifications directly to your go.mod and go.sum files. This write operation is unconditional—whenever you run go get, the command updates your module's declared dependencies to reflect the resolved state. The command may also trigger toolchain upgrades and execute version-control commands for VCS-based modules.

The Cache Population Role of go mod download

In contrast, go mod download functions as a cache-population utility implemented in src/cmd/go/internal/modcmd/download.go. The runDownload function focuses exclusively on fetching module artifacts without changing your build list.

Conditional Metadata Updates

The command calls modload.ListModules to obtain a list of module versions, then downloads each via DownloadModule without altering the main module's dependency graph. By default, go mod download does not modify go.mod or go.sum files.

However, the source code reveals a specific conditional: if haveExplicitArgs || modload.WorkFilePath(moduleLoaderState) != "". This means runDownload only writes to go.mod when you provide explicit module@version arguments or when operating in workspace mode. Otherwise, the command solely writes module files to $GOPATH/pkg/mod/cache/download (or your configured module cache), including .mod, .info, .zip files, and the source tree.

Architectural Comparison: go get vs go mod download

Understanding the architectural split between these commands clarifies when to use each tool:

  • Primary Purpose: go get adjusts dependency metadata to add, upgrade, or remove module requirements, while go mod download populates the local cache with module artifacts for existing requirements.

  • Effect on go.mod: go get unconditionally writes modifications via modload.WriteGoMod after resolving queries. go mod download leaves go.mod unchanged unless explicit arguments are provided or workspace mode is active.

  • Resolution Logic: go get executes complex resolution loops in runGet that handle upgrades, wildcards, and toolchain changes. go mod download performs straightforward enumeration via modload.ListModules followed by artifact fetching.

  • Side Effects: go get may edit checksums, affect the build list, and invoke VCS commands. go mod download only downloads files to the module cache and optionally updates go.sum for explicitly requested modules.

Practical Usage Examples

Use go get when modifying dependencies:


# Add a new dependency and update go.mod / go.sum

go get github.com/google/uuid@v1.3.0

# Upgrade all direct and indirect dependencies to latest minor/patch versions

go get -u ./...

Use go mod download when pre-warming caches:


# Pre-fill the module cache for all transitive dependencies (no go.mod change)

go mod download

# Download a specific module without touching go.mod

go mod download golang.org/x/tools@latest

Summary

  • go get is a dependency management command that mutates go.mod and go.sum to reflect new or changed requirements.
  • go mod download is a cache-population command that fetches module artifacts without changing the module's declared dependencies.
  • The runGet function in src/cmd/go/internal/modget/get.go handles complex resolution and unconditional writes, while runDownload in src/cmd/go/internal/modcmd/download.go performs targeted fetching with conditional metadata updates.
  • Use go get to add, upgrade, or remove dependencies; use go mod download to prepare offline builds or CI environments.

Frequently Asked Questions

Does go mod download modify go.mod?

Generally, no. According to the implementation in src/cmd/go/internal/modcmd/download.go, the runDownload function only writes to go.mod when you provide explicit module@version arguments or when running in workspace mode (detected via modload.WorkFilePath). Standard invocations like go mod download without arguments only populate the module cache without touching your dependency definitions.

When should I use go get versus go mod download in CI pipelines?

Use go mod download in CI pipelines when you want to pre-warm the module cache before running tests or builds, as it downloads all dependencies without modifying go.mod. Use go get only when your CI process needs to update dependencies, such as when implementing automated dependency updates or when the build requires specific versions not yet recorded in go.mod.

Can go mod download upgrade module versions?

No. go mod download does not perform version resolution or upgrades. It downloads the specific versions already recorded in your go.mod file (or those explicitly specified as arguments). To upgrade dependencies, you must use go get, which invokes the resolution logic in runGet to determine newer compatible versions and update your build list accordingly.

How does workspace mode affect these commands?

In workspace mode (using go.work files), both commands adjust their behavior. For go mod download, the conditional check modload.WorkFilePath(moduleLoaderState) != "" in runDownload allows the command to write go.mod files even without explicit arguments. Similarly, go get operates within the context of the workspace, potentially affecting multiple module definitions across the workspace boundary.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →