Code generators belong in your dependency graph
Go 1.24 made tool dependencies explicit. Give generators an owner and a reproducible version, then decide when a separate tool module is justified.
A code generator that changes committed application code deserves a version, an owner and an upgrade decision. Leaving it on a developer's machine makes part of the product's source history depend on an undocumented installation. The business consequence appears when another developer must regenerate a client or repair a build under time pressure.
Looking back from November 2026, that is the useful argument behind Go 1.24's announcement, dated 11 February 2025. It introduced go get -tool to record tool dependencies and go tool to invoke them. The release history confirms the release date. The interesting decision is where a generator belongs in the product's dependency graph and who takes responsibility when its output changes.
Generated output still has inputs
Imagine an application that commits a generated API client. This is an illustrative example, not an AL+ project. A reviewer sees changed method signatures after a schema edit. That difference could come from the schema, the generator version, its configuration or the environment in which it ran. If only the schema is recorded, the review cannot readily separate those causes.
Committing output helps consumers build without installing the generator. It does not explain how that output was produced. The team still needs a documented invocation, the input files and a selected tool version. Otherwise the next regeneration can mix a legitimate product change with unrelated changes from a newer executable.
The Go 1.24 release notes describe tool directives in go.mod as the supported replacement for the conventional blank-import tools.go workaround. That makes the dependency visible to the module machinery. It also makes tool upgrades easier to find in code review, provided the team actually reviews the module changes.
A shared graph has a cost
Putting a generator in the application module is a reasonable default for a small repository. The source and its production tools travel together. A new maintainer has fewer separate version files to discover, and the generation command can be part of the same documented development entry point.
There is a coupling cost. The module reference, a living document consulted in November 2026, explains that tool dependencies participate in the module graph. A tool and the application can depend on the same underlying module. Version selection then has to satisfy the combined graph; naming a generator version does not isolate all of its dependencies from the application's requirements.
This matters during diagnosis. Adding a tool may produce dependency changes beyond the executable itself. Reviewers should ask which requirements moved and whether application behavior could be affected. A generator dependency should not receive less scrutiny merely because nobody expects to run that executable in production.
The same distinction limits claims about reproducibility. A recorded version removes one source of ambiguity. It does not freeze the operating system, external downloads, environment variables or a generator that embeds timestamps. Treat reproducibility as a property of the complete invocation and its inputs, rather than a promise made by one directive.
When a separate tool module earns its keep
The strongest counterargument is that application dependencies and development tools have different upgrade schedules. A generator may need a dependency version the application cannot yet adopt. A repository may also serve several applications whose tooling should evolve together. In those cases, a separate tool module can make the boundary clearer.
That choice introduces work of its own. Someone must maintain the separate module, make its working directory explicit and ensure the documented command uses its selected versions. A beautifully isolated tool graph is of little value if the release script silently invokes a global executable instead.
Choose separation for a concrete conflict or ownership boundary. Record the reason in the development instructions, together with the person or team that can approve an upgrade. Revisit it when the conflict disappears. Keeping a second module forever because an old workaround once required it creates another maintenance obligation without necessarily buying useful isolation.
Neither layout removes the need to inspect generated differences. A generator release can deliberately change defaults or output structure while remaining a legitimate upstream release. Application reviewers must judge whether the resulting code still implements the intended contract with its callers.
Make regeneration a reviewable operation
A practical policy can begin with one consequential generator. Record its inputs and outputs, how it is invoked and which maintainer owns upgrades. Keep a generator upgrade separate from a schema redesign when possible. Smaller causal changes make it easier to understand why a generated method or validation rule moved.
For deterministic output, a proposed check is to regenerate from a clean checkout and inspect the remaining diff. This is a recommendation, not a test performed for this article. If the tool legitimately emits variable content, identify that content and decide whether it belongs in committed output. Do not normalize away meaningful differences simply to make a check green.
Also distinguish regeneration permission from release permission. A tool that can execute scripts or read local files needs an appropriate execution environment. Recording it in a module file documents a dependency; it does not establish that the executable or its upstream supply chain is trustworthy.
For a present-day adoption, verify the supported Go toolchain and the generator's own requirements. This retrospective establishes what changed in February 2025, not a recommendation to deploy that old release now. The current module reference supports the coupling explanation, while the dated announcement establishes the historical feature.
In custom software development, handover should leave the next maintainer able to explain a generated change. Start with the generator whose disappearance would block a release. Give it an owner and a recorded invocation, then decide whether the application graph or a separate tool module best expresses that responsibility.
Paul