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

> Understand the core difference between go get and go mod download for Go module management. Discover how go get updates requirements while go mod download caches modules without changes.

- Repository: [Go/go](https://github.com/golang/go)
- Tags: deep-dive
- Published: 2026-02-16

---

**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`](https://github.com/golang/go/blob/main/src/cmd/go/internal/modget/get.go) and the other managing artifact caching in [`src/cmd/go/internal/modcmd/download.go`](https://github.com/golang/go/blob/main/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`](https://github.com/golang/go/blob/main/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`](https://github.com/golang/go/blob/main/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:

```bash

# 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:

```bash

# 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`](https://github.com/golang/go/blob/main/src/cmd/go/internal/modget/get.go) handles complex resolution and unconditional writes, while `runDownload` in [`src/cmd/go/internal/modcmd/download.go`](https://github.com/golang/go/blob/main/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`](https://github.com/golang/go/blob/main/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.