Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
171: Vendoring Dependencies
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.gitignoreit, you've defeated the entire purpose of the process. - Warning: Your repository size will grow. If you have massive dependencies, your
git clonetimes 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/uuiddependency to your project and use it inmain.goto print a random UUID to the console. - Run
go mod vendorto create the local dependency copy. - To simulate an "air-gapped" or offline environment, run your build command using the
-mod=vendorflag. - The Challenge: To truly prove it works, temporarily rename your
go.modfile togo.mod.bakand try to rungo build -mod=vendor. Observe how Go relies solely on thevendor/folder to resolve theuuidpackage, bypassing the usual module resolution logic.
There are no comments for now.