Golang Dependency Management — Doing it Right!

Breaking free from vendoring chains (Picture by Pixabay)

Go 1.11 introduced support for Go Modules and with it the ability to do proper dependency management. As the Go community moves towards the adoption of modules more and more, the question is “why not stick with vendoring?

  • Source control: Source control is meant to control source code (the name kind of implied that 😇) and not your dependencies;
  • Versioning: The app you create has a version and the dependency you rely on has one too, with vendoring it’s impossible to know which version of the dependency you have;
  • Repository size: If you store more data, your repositories will grow as well and those vendor folders can be huge. Also when you commit files their history will remain even if you delete them later on;
  • Local dependencies: With anything except the use of modules you cannot replace an existing dependency with a local dependency to test, for example, a new version;
  • Build time: Larger repos will take more time to clone and build, making it more time-consuming to push your latest update to production;
  • Repeatable builds: Without modules I can build my source against version 1.2 of a dependency and the next morning someone else in my team might build using version 1.3;
  • Immutable builds: If you depend on other software, you need that to be immutable and not changed by a developer that decides to experiment a little;
  • Project management: PRs for the project will list all changes in the vendor tree, making it difficult to perform proper validation of code.

So, why use Go modules and not use vendoring? Because you want to do dependency management in Go the right way!