What's the difference between go get, go mod tidy, and go mod vendor?
Quick Answer
go get <module>[@version] adds, upgrades, or downgrades a specific dependency, updating go.mod/go.sum accordingly — it's the command you reach for when you want to change what a dependency's version is. go mod tidy reconciles go.mod/go.sum with what your code actually imports: it adds any dependency your source references but that's missing from go.mod, and removes any dependency listed in go.mod that nothing in your code actually imports anymore. go mod vendor copies the fully resolved dependency tree into a local vendor/ directory for offline or auditable builds, as covered in the vendoring question. A common workflow is go get to change a specific version, then go mod tidy to clean up the resulting go.mod/go.sum, and go mod vendor only if the project actually vendors its dependencies.
Detailed Answer
These three commands are easy to conflate, but each answers a genuinely different question.
go get: change a specific dependency's version
go get github.com/gin-gonic/gin@v1.9.1 # pin to a specific version
go get github.com/gin-gonic/gin@latest # upgrade to the latest release
go get github.com/gin-gonic/gin@none # remove it entirely from go.mod
This is the command for "I want this dependency at this version," updating go.mod/go.sum to reflect that specific change.
go mod tidy: reconcile go.mod with actual imports
go mod tidy
Before: go.mod lists a dependency your code no longer imports (leftover from a refactor)
go.mod is MISSING a dependency your code newly imports (you forgot to `go get` it)
After go mod tidy:
The unused entry is removed
The missing entry is added, at an appropriate resolved version
go.sum is updated to match
go mod tidy doesn't care what you intended to add or remove — it only cares what your actual source code, right now, imports, and makes go.mod match that reality exactly.
go mod vendor: snapshot dependencies locally
go mod vendor
Copies the fully resolved dependency source tree into vendor/, for the offline/auditability reasons covered in the vendoring question. This doesn't change go.mod at all — it just materializes what go.mod/go.sum already resolved to, as actual files on disk.
A typical real workflow
go get github.com/some/newlib@v2.0.0 # 1. add or change a specific dependency
go mod tidy # 2. clean up go.mod/go.sum to match actual imports
go mod vendor # 3. only if this project vendors dependencies
Running go mod tidy before committing is standard practice, specifically because it catches both "you imported something new and forgot to add it" and "you removed the last usage of something but left it in go.mod" — both of which are easy to miss by hand.