Go resolves dependencies with minimal version selection, which chooses the highest version any module in the graph requires, and nothing newer. The result is deterministic without a separate lockfile, because publishing a new release does not change what your build selects.
How it works
The Go modules reference says MVS starts at the main modules and traverses the requirement graph, tracking the highest required version of each module. The highest required versions form the build list, which are the minimum versions that satisfy all requirements.
It adds that higher versions of a module may exist, but MVS does not select them since nothing requires them.
Compare that with systems that pick the newest version fitting a range. There, a new release can enter your build on its own. In Go, a version enters only when something in your graph asks for it.
No lockfile, by design
The reference states that, unlike other dependency management systems, the build list is not saved in a lock file. MVS is deterministic, and the build list does not change when new versions of dependencies are released, so Go recomputes it at the start of every module aware command. You can inspect it with go list -m all.
Required versions in go.mod are minimum versions and may be raised automatically as new dependencies are added.
What this means for hygiene
Updates are deliberate. Nothing upgrades itself. A vulnerable version stays selected until you or a dependency asks for a fixed one.
You must ask for fixes. Plain go get with a module path uses the upgrade query. The reference says the u flag upgrades modules providing packages imported directly or indirectly by the named packages, to their latest version. The patch variant, written -u=patch, upgrades each to the latest patch release.
go get golang.org/x/net
go get -u ./...
go get -u=patch ./...
Check the build list after changes. Run go list -m all and compare it with what you expect.
Where integrity comes from
Without a lockfile, the go.sum file holds checksums that verify downloaded modules. Commit both go.mod and go.sum. For what go.sum and the checksum database protect against, see Go module checksum database in depth.
Common misunderstandings
- No lockfile does not mean no reproducibility. The go.mod graph plus MVS gives it.
- Minimum does not mean old and unpatched forever. It means as old as your requirements allow, so a missing fix needs an explicit request.
- A new release of a dependency will not reach you until a requirement changes, which is good for stability and bad for passive patching.
Pairing with scanning
Because versions never float, a vulnerability scan on your build list tells you exactly what you run. Safeguard's SBOM and dependency scanning can scan Go projects, and you can try a free scan at gold.safeguard.sh/scan.
Quick check
Does Go pick the newest compatible version?
No. It picks the highest version any requirement names, which is the minimum that satisfies the graph.
How do I see what my build uses?
Run go list -m all to print the build list.
Sources
Last reviewed: 19 October 2026.