Skip to Content
Course content

171: Vendoring Dependencies

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've likely spent the last few lessons getting comfortable with Go modules. You have a go.mod and a go.sum file, and everything feels seamless. Because of this, many developers fall into a specific trap: they assume that because their dependencies are "locked" in go.mod, their build is fully reproducible and safe from external failures.

Thinking go.mod is a complete backup

It's a common mistake to think that go.mod is a snapshot of your dependencies. It isn't. It's a manifest—a list of pointers. When you run go build, Go looks at that list, checks your local module cache, and if the code isn't there, it reaches out to the Go proxy or the original version control system (like GitHub) to download it.

Here is where that logic fails in the real world. Imagine you're using a library like github.com/google/uuid. Your go.mod is perfect. But then, one of three things happens: the Go proxy has a major outage, the library author deletes the repository, or you're deploying to a high-security CI/CD runner that has no outbound internet access for security reasons. Suddenly, your "reproducible" build crashes because the instructions for the build are present, but the actual source code is missing.

Guaranteeing builds with go mod vendor

This is where vendoring comes in. Vendoring is the act of physically copying the source code of your dependencies into a directory called vendor/ inside your own project root. I'll admit, it feels like a regression to the "wild west" days of software engineering where we committed libraries to Git, but in a professional Go environment, it's often a necessity for stability.

When you run go mod vendor, Go creates that vendor/ directory and populates it with every package your project needs. Now, your dependencies are no longer just pointers on a list; they are actual files in your repository.

# This command creates the vendor folder based on your go.mod
go mod vendor

Once that folder exists, Go changes its behavior. By default, if a vendor/ directory is present in the root of your main module, Go will use it instead of the network or the local module cache. If you want to be explicit—or if you're using an older version of Go—you can use the -mod=vendor flag:

go build -mod=vendor main.go

I usually recommend vendoring for any project that will be maintained for years or deployed in restrictive environments. It removes the "network" variable from your build pipeline. You aren't trusting a proxy or a third-party maintainer to keep their repo alive; you own the code you are shipping.

  • Pro tip: If you decide to vendor, you must commit the vendor/ folder to your version control (Git). If you .gitignore it, you've defeated the entire purpose of the process.
  • Warning: Your repository size will grow. If you have massive dependencies, your git clone times will increase. It's a trade-off: disk space and clone time versus absolute build reliability.



📋 Practical Task

Simulating an Air-Gapped Build with a Vendored UUID Library

In this exercise, you will create a small program that depends on an external library, vendor that library, and then verify that the program can build even when the Go toolchain is forbidden from accessing the network.

Requirements:

  • Initialize a new module named vendor-test.
  • Add the github.com/google/uuid dependency to your project and use it in main.go to print a random UUID to the console.
  • Run go mod vendor to create the local dependency copy.
  • To simulate an "air-gapped" or offline environment, run your build command using the -mod=vendor flag.
  • The Challenge: To truly prove it works, temporarily rename your go.mod file to go.mod.bak and try to run go build -mod=vendor. Observe how Go relies solely on the vendor/ folder to resolve the uuid package, bypassing the usual module resolution logic.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.