LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 4119 min read

Go Modules & Dependencies

Learn how to add third-party dependencies with go get, how Go uses semantic versioning, and how go.sum guarantees dependency integrity.

Introduction

You already met go.mod and go.sum briefly when creating your own module. This lesson goes deeper into how Go actually manages third-party dependencies: fetching them, pinning specific versions, and guaranteeing that the exact same code is used every time your project is built, on any machine.

What You Will Learn
  • How to add a third-party dependency with go get.
  • What actually happens under the hood when you run go get.
  • How Go uses semantic versioning to select dependency versions.
  • What go.sum records and why it matters for security and reproducibility.
  • How to update or remove dependencies safely.

Adding a Dependency

Suppose you want to use the popular google/uuid package to generate unique identifiers. You add it with go get, then simply import and use it — Go automatically records it in go.mod.

go get github.com/google/uuid
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
id := uuid.New()
fmt.Println("generated ID:", id)
}
Output (a fresh UUID each run)

Click Run to see what this code prints.

How go get Works

When you run go get, Go fetches the source code for the requested module (from its version control host, or from a module proxy like proxy.golang.org by default), verifies it against the public checksum database, and records the exact version in go.mod and its checksum in go.sum.

go.mod after adding a dependency
module github.com/yourname/mytool
go 1.22
require github.com/google/uuid v1.6.0

You can also fetch a specific version explicitly, or upgrade/downgrade an existing one, by appending @version.

go get github.com/google/uuid@v1.6.0 # a specific version
go get github.com/google/uuid@latest # the latest release
go get github.com/google/uuid@none # remove the dependency

Semantic Versioning

Go modules are versioned using semantic versioning: vMAJOR.MINOR.PATCH. Go's tooling relies on this format to decide what "compatible" means when resolving dependency versions across your whole module graph.

Version PartMeaningExample
MAJORBreaking changes to the public APIv1.x.x → v2.x.x
MINORNew backward-compatible functionalityv1.5.x → v1.6.x
PATCHBackward-compatible bug fixesv1.6.0 → v1.6.1
Major Version Suffixes

Starting at v2, Go requires the major version to appear in the import path itself, e.g. github.com/some/module/v2. This is Go's way of allowing incompatible major versions to coexist without ambiguity.

go.sum and Integrity Checks

go.sum stores a cryptographic hash for every version of every module your project depends on, directly or transitively. Every time you build, Go re-verifies downloaded module code against these hashes — if anything does not match (for example, a compromised or tampered package), the build fails immediately instead of silently using different code.

a snippet of go.sum
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

You should never hand-edit go.sum. It is fully managed by the go command as a byproduct of go get, go build, go mod tidy, and similar commands.

Updating and Removing Dependencies

go mod tidy is the command you will run most often: it adds any missing dependencies your code actually imports and removes any that are no longer used, keeping go.mod and go.sum accurate.

go mod tidy # sync go.mod/go.sum with actual imports
go get -u ./... # upgrade all dependencies to their latest minor/patch
go list -m all # list every module in the build, with versions
Sample go list -m all output

Click Run to see what this code prints.

Common Mistakes

Avoid These Mistakes
  • Hand-editing go.sum, which breaks its integrity guarantees.
  • Committing go.mod without go.sum (or vice versa), leaving builds unreproducible.
  • Running go get -u ./... blindly right before a release without testing the upgraded dependencies.
  • Importing a v2+ module without the required /v2 suffix in the import path.
  • Vendoring dependencies and then forgetting to keep the vendor directory in sync with go.mod.

Best Practices

  • Run go mod tidy before committing, so go.mod/go.sum always reflect actual usage.
  • Pin dependencies to specific, tested versions rather than always chasing @latest.
  • Review the diff of go.mod/go.sum in every pull request, just like any other code change.
  • Use go list -m all periodically to audit exactly what your build depends on.
  • Keep both go.mod and go.sum committed to version control at all times.

Frequently Asked Questions

A direct dependency is one your own code imports. An indirect dependency is one required by a direct dependency, marked with a "// indirect" comment in go.mod, that your code does not import directly.

Yes. Because major versions v2 and above require a version suffix in the import path (e.g. /v2), Go can treat them as entirely separate modules and both can be imported in the same build if needed.

The build fails immediately with a security error. This is intentional — it means the fetched code differs from what was originally verified, which could indicate tampering or a compromised source.

Key Takeaways

  • go get adds or updates a dependency and records it in go.mod, with its checksum in go.sum.
  • Go modules use semantic versioning (MAJOR.MINOR.PATCH) to resolve compatible versions.
  • go.sum guarantees that the exact same dependency code is used on every machine and every build.
  • go mod tidy keeps go.mod and go.sum accurate and free of unused dependencies.
  • Major versions v2+ require a version suffix in the import path.

Summary

Go's module system gives you reproducible builds and verifiable dependency integrity without extra tooling — go get, go.mod, and go.sum work together seamlessly. With dependency management covered, the final lesson of this course pulls everything together: idiomatic style, building production binaries, and deploying Go applications.

Next Lesson →

Best Practices & Deployment