ProgrammingGo Developer

How do go modules and dependency management work in Go? What pitfalls can arise when updating or locking dependencies?

Pass interviews with Hintsage AI assistant

Answer

Go Modules is the standard dependency management mechanism introduced in Go 1.11+. The main files are go.mod (which defines the minimum dependencies and their versions) and go.sum (which ensures integrity through hashes).

To add a dependency, use:

go get github.com/pkg/errors@v0.9.1

To update dependencies:

go get -u ./... go mod tidy # remove unused

Go supports semantic versioning (semver), and dependencies are tightly locked: the project is reproducible, and the build is deterministic. However, keep in mind:

  • Using replace paths (<replace github.com/pkg/errors = ../errors>) poses risks of incompatibility.
  • A mistake when manually editing go.mod can lead to version incompatibility and conflicts with transitive dependencies.
  • Some dependencies use another system (dep, vendoring), which complicates migration.

Trick Question

What happens if you delete the go.sum file and run the go build command, and why is it dangerous?

Many think that Go simply rebuilds the dependencies from scratch. But the go.sum file contains hashes of all used modules and protects against tampering (supply-chain attack). If it is deleted, at the next build, Go will download the dependencies again, recreate the file, but if the dependency repository has been altered by a malicious actor — the protection is broken! Code substitution in production is possible.

Examples of real mistakes due to ignorance of topic nuances


Story

On a large project, the repository transitioned from vendoring to go modules, but they forgot to lock the versions. A month later, updates to third-party packages broke compatibility, making it impossible to build the old branch — the code lost reproducibility.


Story

In another project, a developer accidentally deleted go.sum. After restarting, the team noticed that some dependencies had changed, causing bugs related to minor version incompatibility — this resulted in a rollback several days back.


Story

Using replace paths for local directories (replace ... = ../some/library) was not removed before deployment — in the CI/CD pipeline, the build failed because the external system did not have access to local files, and production became "pinned" to an incorrect version.