One Tool To Rule Them All

The release of Go 1.24 introduces the tool directive for Go modules 1. This command simplifies the process of managing tools like liners, generators or task runners. The usual approach up to this point was to install all related tools outside the project directory. Usually using operating system package manager like beloved pacman 2. This approach by its own is not that bad but requires managing the dependencies from outside the project itself. The go tool allowes us to manage these tools’ dependencies from within the project directory.

As an example we wil install a task tool that runs commands from a Taskfile.yml 3.

$ go get -tool github.com/go-task/task/v3/cmd/task@latest

What exactly happens when we do this?

  • Go reads the -tool flag and the module path with the @latest version query. it signals that this dependency should be tracked as a tool dependency, not a regular library import.
  • Go contacts the module proxy (controlled by GOPROXY enviorement variable, default is proxy.golang.org) and asks what is the latest tagged version of github.com/go-task/task/v3? The proxy responds with the most recent semver tag like v3.50.0.
  • Go downloads the module’s source code and stores it in the local module cache (GOPATH/pkg/mod/).
  • The go.mod file is updated with a line tool github.com/go-task/task/v3/cmd/task and a resolved version is added to require block.
  • Go computes and records cryptographic checksums for the downloaded module in go.sum, ensuring reproducible builds 4.
  • Go does not place a binary in $GOPATH/bin, instead it will be compiled the first time You invoke the command and placed somewhere inside the GOCACHE directory. For me, it is : GOCACHE/db/[hash]/task.

We can confirm that indeed the tool is a compiled go binary:

$ go version -m /home/mp/.cache/go-build/db/dbaf4dccb08d0a7e2fb38ec6b15f8cae110b7c39119c9382854dfc378b56752d-d/task
/home/mp/.cache/go-build/db/dbaf4dccb08d0a7e2fb38ec6b15f8cae110b7c39119c9382854dfc378b56752d-d/task: go1.26.2-X:nodwarf5
	path	github.com/go-task/task/v3/cmd/task
	(...)

Now we can run the actual tool with go tool task. To see what will be called (instead of actually running the command) add -n like this go tool -n task.

One imporant aspect to remember is that the adding a tool to project does not automatically update the $PATH. If this is required for some reason, we have to update it ourselves.

There is a slightly negative aspect to using go tool. The go.mod file can grow siginificantly with indirect dependencies.

The go tool command allows us to manage project tools from within the project directory by using the same go.mod that we use for other module dependencies. This simplifies tracking of all the dependencies for the project.

To summarize:

  • The -tool approach is the idiomatic way to manage development tools (linters, generators, task runners)
  • Tools are clearly separated from the code dependencies in the go.mod file
  • Tools can be locked to specific versions that guarantee their consistent behavior
  • We have one tool for managing tools, which simplifies installing, updating and removing of tools

Copyright © 2026 by Michal Przybylowicz