最直接的方式是用go mod vendor将依赖复制到vendor/目录,但需先确保有go.mod文件;构建时必须显式加-mod=vendor参数才生效,否则仍走远程缓存。

go mod vendor 生成本地依赖副本
本地持久化依赖最直接的方式是用 go mod vendor 把所有依赖复制到项目根目录下的 vendor/ 目录。这不是“缓存”,而是显式拷贝:Go 会读取 go.mod 和 go.sum,下载并解压每个依赖模块的指定版本,放进 vendor/ 中对应路径。
执行前必须确保已有 go.mod 文件;如果没有,先运行 go mod init your-module-name。之后运行:
go mod vendor
注意:vendor/ 不包含测试专用依赖(仅被 _test.go 引用、未被主代码引用的包),也不会处理 replace 指令指向的本地路径——那些路径被跳过,不复制。
- 生成后,
vendor/目录结构与 import 路径严格一致,例如github.com/sirupsen/logrus会落在vendor/github.com/sirupsen/logrus/ - 建议把
vendor/提交到 Git,否则协作时别人拉代码后无法复现相同构建环境 - 更新依赖后,需先
go mod tidy清理冗余项,再重新go mod vendor,否则旧包可能残留
构建时必须加 -mod=vendor 才真正使用本地副本
光有 vendor/ 目录并不等于构建时就用了它。默认情况下,go build 仍会从 $GOPATH/pkg/mod 缓存加载模块,vendor/ 被完全忽略。
立即学习“go语言免费学习笔记(深入)”;
要强制走本地,必须显式传参:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
go build -mod=vendor
漏掉这个参数,CI 构建很可能和本地行为不一致——你本地改了 vendor/ 里的某行代码,但构建结果没变,就是因为根本没读它。
-
go run、go test同样需要加-mod=vendor才生效 - 编辑器(如 VS Code)中 gopls 默认不启用 vendor 模式,需在设置里加
"build.buildFlags": ["-mod=vendor"] - 若设
GOPROXY=off并删掉$GOPATH/pkg/mod/cache,不加-mod=vendor就会直接报错,这是验证是否生效的快捷方式
replace 不能替代 vendor,但可配合调试本地模块
replace 是开发期路径重定向,不是本地持久化手段。它让 Go 在编译时跳过远程下载,直接读取你本地文件系统上的模块路径,比如:
replace github.com/yourorg/utils => ./utils
这条声明写在 go.mod 里,go mod vendor 会跳过它——vendor/ 里不会出现 ./utils 的内容,只保留其他远程依赖。
- 适合多模块联调:主项目引用尚未发布的子模块,或正在热修的私有库
- 发布前必须删除
replace行,否则 CI 构建失败(找不到./utils) - 如果子模块本身也有
go.mod,它的module名必须和replace左侧完全一致(大小写敏感)
go.sum 是校验基础,不能省略或忽略
go.sum 不是可选文件,它是本地持久化的完整性保障。它记录每个依赖模块的 SHA256 校验和,无论你用 vendor/ 还是远程缓存,每次 go build 都会核对实际内容是否匹配。
这意味着:
-
go.sum必须提交到 Git,否则不同机器上go mod vendor生成的vendor/内容可能不一致 - 不要手动编辑
go.sum,出问题时用go mod verify检查,或删掉后跑go mod tidy重建 - CI 流程里若禁用校验(如设
GOSUMDB=off),等于放弃防篡改能力,风险极高
真正可靠的本地持久化,是 go.mod + go.sum + vendor/ + -mod=vendor 四者协同;少一个环节,就可能在某个环境里悄悄失效。

















