go mod download 下载的是全局模块缓存而非项目级缓存,将模块解压存至$GOMODCACHE(如$HOME/go/pkg/mod),所有项目共享;默认只下载go.mod中显式声明的直接依赖,不包含indirect依赖,需用go mod download all才能覆盖完整模块图。

go mod download 下载的到底是不是“本地缓存”
不是项目级缓存,而是全局模块缓存。它把 github.com/some/pkg@v1.2.3 这类模块解压后存到 $GOMODCACHE(通常是 $HOME/go/pkg/mod),所有项目共用同一份。你执行 go mod download,它不会往你项目目录里放任何东西,也不会生成 vendor/;只是确保这个路径下有了可验证的源码副本。
常见误解是以为“下载完就能离线 build”,但实际得看两点:
– go.mod 里有没有漏掉 // indirect 依赖(go mod download 默认不拉)
– go.sum 校验是否通过(失败会直接退出,不跳过)
- 查真实缓存位置:运行
go env GOMODCACHE - 确认是否已缓存:
go list -m github.com/some/pkg不报错且无 downloading 日志,说明已就位 - 别手动删
$GOMODCACHE/github.com/...子目录——checksum 会失效,要用go clean -modcache
想真正离线构建,光 run go mod download 不够
默认 go mod download 只拉 go.mod 中 require 块显式声明的模块,不包含未被直接 import 的 // indirect 依赖。而 go build 过程中一旦遇到没缓存的间接依赖,仍会触发网络请求。
正确做法是用 go mod download all —— 注意,这里的 all 是关键字,不是通配符。它等价于 go list -m all | xargs go mod download,会覆盖整个模块图(包括所有 indirect 模块),但有两个例外:
- 被
replace指向本地路径的模块(如replace example.com/a => ./local/a)不下载 - 被
exclude排除的模块,只要go list -m all还能列出来,就会下
执行前务必先 go mod tidy,否则 go.mod 可能缺失依赖项,go list -m all 输出就不全。
CI/CD 或离线环境怎么复用这份缓存
核心是持久化 $GOMODCACHE 目录,而不是每次重下。不同场景策略不同:
- Docker 构建:在
COPY代码前加RUN go mod download,让依赖层独立缓存;再配合--mount=type=cache,target=/home/go/pkg/mod(BuildKit)避免重复拉取 - GitHub Actions:用
actions/cache@v4缓存~/go/pkg/mod,key 基于go.sumhash - 离线机器部署:打包
$GOMODCACHE整个目录,解压到目标机相同路径,并设GOPROXY=off GOSUMDB=off
注意:如果项目用了 replace 到远程 URL(比如 replace example.com/a => https://github.com/x/a v1.2.0),go mod download all 会跳过它——Go 认为这是构建时才需解析的重定向,得等 go build 阶段才去抓。
为什么有时候 go mod download all 会卡住或失败
没有进度条,卡顿几秒是正常现象——它正在解析模块版本、发起并发 HTTP 请求、校验 checksum。容易出问题的点集中在:
-
go.sum被手动修改过:校验失败直接报verifying github.com/xxx@v1.2.3: checksum mismatch,必须修复或重跑go mod tidy - 某些模块域名被防火墙拦截,但 GOPROXY 设置为
direct:比如私有域名git.company.com实际不可达,go mod download all会 hang 住或超时退出 - 模块含
//go:embed或 cgo:这些特性可能触发额外的构建逻辑,导致go list -m all没覆盖到全部依赖,build 阶段仍要联网
调试时加 -x 参数看底层命令(如 go mod download -x),能明确看到哪些模块在 fetch、走的是 proxy 还是 direct。

















