TL;DR: a proposta de diretiva tool no go.mod formaliza um problema antigo em projetos Go: como declarar, versionar e executar ferramentas de desenvolvimento sem depender de instalação global nem de um tools.go artificial. Desde Go 1.24, esse caminho aparece na documentação do toolchain: o módulo pode listar ferramentas com tool, controlar suas versões via require e executá-las com go tool. Para times que usam geradores, linters, migradores ou CLIs internas, é uma mudança pequena no arquivo, mas grande na reprodutibilidade.
O problema que o tools.go tentava resolver
Muitos repositórios Go dependem de programas escritos em Go para tarefas fora do binário principal. Pense em stringer, mockgen, oapi-codegen, geradores de protobuf, migradores de banco ou CLIs internas em ./cmd/migrate. Essas ferramentas fazem parte do desenvolvimento do projeto, mas nem sempre fazem parte do código compilado para produção.
Antes da diretiva tool, a prática comum era criar um arquivo tools.go com build tag, importando os pacotes das ferramentas apenas para forçar o go.mod a registrar as dependências:
//go:build tools
package tools
import _ "golang.org/x/tools/cmd/stringer"
Funciona, mas é um truque. Quem chega no projeto precisa entender a build tag, lembrar de atualizar versões com cuidado e muitas vezes ainda rodar comandos longos como go run golang.org/x/tools/cmd/stringer@.... Em CI, o risco é cada job instalar uma versão diferente. Em máquinas locais, o risco é pior: uma ferramenta global antiga pode gerar código diferente do que o repositório espera.
Como a diretiva tool organiza isso
A proposta adiciona uma diretiva explícita ao go.mod:
module exemplo.com/app
go 1.24
tool golang.org/x/tools/cmd/stringer
require golang.org/x/tools v0.30.0
Também é possível usar bloco:
tool (
golang.org/x/tools/cmd/stringer
github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen
./cmd/migrate
)
A versão continua sendo responsabilidade do grafo de módulos, via require e, quando necessário, replace. A diretiva tool diz quais pacotes são ferramentas do projeto; o require diz qual versão entra na resolução.
Na prática, o fluxo documentado é direto. Para adicionar uma ferramenta:
go get -tool golang.org/x/tools/cmd/stringer
Para executar dentro do módulo:
go tool stringer -type=Estado
E, se houver ambiguidade entre duas ferramentas com o mesmo nome final, dá para chamar pelo caminho completo:
go tool golang.org/x/tools/cmd/stringer -type=Estado
A documentação do Go também descreve o metapadrão tool, que representa as ferramentas declaradas no módulo. Isso permite ações como instalar ou preparar todas elas de uma vez, dependendo do comando usado.
Por que isso importa no dia a dia
O ganho principal é tirar ferramentas de desenvolvimento do campo “cada um configura do seu jeito”. Se o repositório declara a ferramenta no go.mod, revisão de código, CI e onboarding passam a ter uma fonte única de verdade.
Isso é especialmente útil em projetos com código gerado. No guia de OpenAPI com Go e oapi-codegen, a recomendação prática já era fixar a versão da ferramenta no projeto, não confiar em uma instalação solta. A diretiva tool torna esse padrão mais nativo: o contrato fica no go.mod, junto das dependências do módulo.
Também ajuda CLIs internas. Um projeto pode manter ./cmd/migrate ou ./cmd/gendocs como ferramenta do próprio módulo e executá-la com o mesmo mecanismo usado para ferramentas externas. Para quem cria ferramentas de linha de comando, o tutorial de CLI tools em Go continua valendo; a novidade é como um projeto consumidor pode declarar e rodar essas ferramentas de forma consistente.
Outro detalhe importante é performance e ergonomia. A proposta compara esse fluxo com go run, que pode recompilar ou relinkar ferramentas repetidamente. O desenho prevê cache de binários em área ligada ao $GOCACHE, permitindo execuções repetidas mais rápidas sem transformar isso em instalação global permanente.
O que muda para projetos existentes
Se o projeto já usa tools.go, não há urgência automática. O padrão antigo continua compreensível para versões anteriores do Go e ainda aparece em muitos repositórios. A migração começa a fazer sentido quando o projeto já exige Go 1.24 ou superior, ou quando o time quer reduzir boilerplate em ferramentas compartilhadas.
Um caminho simples é converter cada import de ferramenta em uma linha tool, rodar go mod tidy e ajustar scripts de CI para usar go tool nome em vez de go run pacote ou binários globais. Para ferramentas chamadas por go generate, o comando também pode ficar mais curto e menos dependente do ambiente local.
Ainda existem limites. A diretiva cobre ferramentas distribuídas como pacotes Go. Ela não substitui gerenciadores de binários arbitrários, não instala Node, Docker, protoc ou utilitários do sistema operacional. Também vale atenção a conflitos de nome: se duas ferramentas terminam com o mesmo nome, prefira o caminho completo no script.
O sinal maior para o ecossistema
A mudança é pequena, mas combina com uma força histórica do Go: o toolchain tenta resolver fluxos comuns sem exigir uma pilha paralela de gerenciadores. Módulos já resolveram boa parte da reprodutibilidade de bibliotecas. A diretiva tool aplica a mesma ideia ao entorno do desenvolvimento.
Para times brasileiros que mantêm vários serviços Go, isso reduz atrito em tarefas repetidas: gerar mocks, atualizar clientes OpenAPI, rodar migrações locais, validar schemas e preparar releases. Menos instruções “instale a versão certa dessa ferramenta” no README; mais configuração versionada no repositório.
O melhor próximo passo é olhar para o seu Makefile, scripts de CI e arquivos tools.go. Se existe ferramenta Go essencial ao projeto, ela provavelmente é candidata a virar uma entrada tool no go.mod.