What is vendoring, and when would you still use it in the module era?
Quick Answer
Vendoring means copying all of a project's dependencies' source code directly into a vendor/ directory inside the repository itself, checked into version control alongside your own code. go mod vendor generates this directory from your current go.mod/go.sum, and go build -mod=vendor (or the default behavior when a vendor/ directory with a valid manifest exists) builds using those local copies instead of the module cache. Reasons to still vendor today: guaranteeing a build works with zero network access (air-gapped environments, strict CI sandboxes), auditability (all dependency source is directly visible and diffable in your own repo, not just referenced by version), and protection against a dependency becoming unavailable from the proxy for any reason. The tradeoff is repository size and the overhead of re-running go mod vendor after every dependency change.
Detailed Answer
Vendoring predates Go modules entirely (it was the standard dependency-management approach before modules existed), but it's still a legitimate, supported option today for specific situations.
Generating a vendor directory
go mod vendor
vendor/
github.com/gin-gonic/gin/
...full source of the dependency...
modules.txt # a manifest recording exactly which versions are vendored
Building from vendored dependencies
go build -mod=vendor ./...
If a vendor/ directory with a valid modules.txt exists and your Go version is 1.14+, go build actually uses vendored code by default, without needing the explicit flag, unless you override it.
When vendoring earns its cost
- Air-gapped or heavily restricted build environments that have no outbound network access at all, where fetching from any proxy is impossible during the build itself.
- Regulatory or audit requirements, where every byte of shipped code must be reviewable directly inside the same repository, not just referenced by a version number pointing elsewhere.
- Extra protection against dependency unavailability, beyond what the module proxy's caching already provides, for organizations with particularly strict reliability requirements.
The tradeoff
vendor/ can easily add tens of megabytes (or more) to a repository,
and needs `go mod vendor` re-run (and the diff committed) every time
a dependency changes.
For most projects today, the module proxy plus go.sum verification already provides enough reproducibility and availability guarantees, which is why vendoring is the exception rather than the default in modern Go projects — but it remains a fully supported, sometimes necessary option, not a deprecated relic.