What does the Go 1.24 tool directive replace, and how do you use it?
Question 421MediumGo 1.22 to 1.25
Before 1.24 the convention was a tools.go file with //go:build tools and blank imports, used to pin versions of developer tools (stringer, mockgen, sqlc) in go.mod. Go 1.24 made this a first-class feature: a tool directive in go.mod, run with go tool.
go get -tool golang.org/x/tools/cmd/stringer@v0.28.0
# go.mod gains:
tool golang.org/x/tools/cmd/stringer
go tool stringer -type=Color # builds (cached) and runs the pinned version
go get tool # upgrade all tools
go install tool # install all tools into GOBIN
//go:generate go tool stringer -type=Color
Benefits: tool versions go through MVS and go.sum like any other dependency, every developer and CI job runs the same version, there is no go install step and no $PATH drift, and executables are cached in the build cache.
Gotchas: tool dependencies join your module graph and can raise versions of shared libraries, since MVS applies to them too. If that becomes a problem, put tools in a separate module (go tool -modfile=tools/go.mod). Remove a tool with go get -tool pkg@none.
More on Modules, Packages & Tooling
- Q419What do the go and toolchain directives mean since Go 1.21, and how does GOTOOLCHAIN behave?
- Q420What does this print? (Hint: consider the go line in go.mod.)
- Q422What is the difference between go get and go install pkg@version in module mode?
- Q423Explain build constraints: the //go:build syntax, filename rules, and common gotchas.
- Q424How would you separate integration tests from unit tests using build tags? What alternatives exist?
- Q425How does go generate work, and what are best practices around it?