Go version
go 1.24 linux/amd64
Output of go env
in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/dkoptev/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/dkoptev/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build581616536=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/dkoptev/cyp-services/cyp-firmware-manager/go.mod'
GOMODCACHE='/home/dkoptev/go/pkg/mod'
GONOPROXY='yadro.dev/*'
GONOSUMDB='yadro.dev/*'
GOOS='linux'
GOPATH='/home/dkoptev/go'
GOPRIVATE='yadro.dev/*'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go-1.24.5'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/dkoptev/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go-1.24.5/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.5'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
When I import some third-party package of some third-party module,
Go has an optimization that adds only dependencies of the package being imported to the my go.mod
, but not all dependencies of the third-party module. This is good optimization because only dependencies of the imported package need to be statically linked into my binary during build.
But I have a problem when dependencies are common to the my module and to the third-party module, but not needed in the package I'm importing from this third-party module. Optimization does not work here.
To be more specific:
- My module has a dependency on, let's say,
go.uber.org/zap/exp
-
I want to import the package
hello
of the third-party moduleexample.com/abc/example-module
, so I dogo import "example.com/abc/example-module/hello"
-
The module
example-module
also hasgo.uber.org/zap/exp
in itsgo.mod
, but itshello
package does not import it. If I didn't have the dependency onzap/exp
, everything would be fine and I wouldn't even seezap/exp
in mygo.mod
. But my code also depends onzap/exp
. - When I do
go get example.com/abc/example-module@some_version
, I see thatgo.uber.org/zap/exp
is also updated in mygo.mod
since it is newer inexample.com/abc/example-module
go.mod
.
What did you see happen?
zap/exp
is also updated when I'm updating the module that depends on it
go: upgraded go.uber.org/zap/exp v0.1.0 => v0.2.0
What did you expect to see?
Since hello
package does not import go.uber.org/zap/exp
, I'd expect that there is no need to bump zap/exp
similar to how there is no need to add a new dependency to my go.mod
if it is only present in the third-party module's go.mod
, but not imported in its hello
package. It should be ok to keep linking with the old zap version, that my code needs. But the optimization does not work here.
Could you tell me, please, is this behavior expected? Can we fix it and apply the same optimization?
Comment From: mknyszek
CC @golang/command-line
Comment From: seankhliao
I believe this is working as intended. An entry in go.mod records resolved versions, which is necessary when the dependency graph is more complex. It doesn't imply that a dependency is linked into the final binary.
There is nothing to fix.
Comment From: gabyhelp
Related Issues
- cmd/go: module update should drop unused indirect dependencies? #26474
- toolchain: Minimal version selection applies to indirect dependencies even when they are module-local #69798 (closed)
- cmd/go: `go get -u` on main module bloats go.mod with unnecessary dependencies #33102 (closed)
- cmd/go: go test ./... or go build should not update existing dependencies and only add new dependencies as needed to satisfy imports #37780 (closed)
- cmd/go: document how to get 'go mod tidy' to keep an unused dependency #37352 (closed)
- cmd/go: no 'go get' command promotes an implicit dependency to an explicit one #43131 (closed)
- cmd/go: go get -u on a single module results in indirect modules being updated too #28156 (closed)
- cmd/go: downgrading a module with `go get` retains indirect dependencies #26481 (closed)
- cmd/go: go build, list etc can upgrade existing dependency versions #28692 (closed)
- cmd/go: 'go mod download' pulls in test dependencies of dependencies #41431 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: denis-koptev
@seankhliao thanks for your answer! I have one more question. If entries in go.mod are about dependent modules' versions why do we have an optimization that skips dependencies which are present in a third-party go module but are not imported in a package within this module that we import in our code? And why don't we have the same optimization if I import the same package of the same module, but unfortunately I have the same dependent module as third-party module has, but third-party package I'm importing in my code does not import this dependency? It seems pretty the same...