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 getadjusts dependency metadata to add, upgrade, or remove module requirements, whilego mod downloadpopulates the local cache with module artifacts for existing requirements. -
Effect on
go.mod:go getunconditionally writes modifications viamodload.WriteGoModafter resolving queries.go mod downloadleavesgo.modunchanged unless explicit arguments are provided or workspace mode is active. -
Resolution Logic:
go getexecutes complex resolution loops inrunGetthat handle upgrades, wildcards, and toolchain changes.go mod downloadperforms straightforward enumeration viamodload.ListModulesfollowed by artifact fetching. -
Side Effects:
go getmay edit checksums, affect the build list, and invoke VCS commands.go mod downloadonly downloads files to the module cache and optionally updatesgo.sumfor 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 getis a dependency management command that mutatesgo.modandgo.sumto reflect new or changed requirements.go mod downloadis a cache-population command that fetches module artifacts without changing the module's declared dependencies.- The
runGetfunction insrc/cmd/go/internal/modget/get.gohandles complex resolution and unconditional writes, whilerunDownloadinsrc/cmd/go/internal/modcmd/download.goperforms targeted fetching with conditional metadata updates. - Use
go getto add, upgrade, or remove dependencies; usego mod downloadto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →