Skip to content

Instantly share code, notes, and snippets.

@devops-school
Created August 18, 2026 05:04
Show Gist options
  • Select an option

  • Save devops-school/ac5c206be83aa0c16120d645f3e39227 to your computer and use it in GitHub Desktop.

Select an option

Save devops-school/ac5c206be83aa0c16120d645f3e39227 to your computer and use it in GitHub Desktop.
Hands-On Lab: Dependency Management with Go Modules

Hands-On Lab: Dependency Management with Go Modules

Goal: Experience the complete dependency-management lifecycle in a real Go project: initialize a module, add dependencies, inspect go.mod and go.sum, pin and change versions, understand direct and indirect dependencies, clean the module graph, verify downloads, use the module cache, explore vendoring, and configure private-module behavior.

Lab Overview

By the end of this lab, you will be able to:

  1. Explain the difference between a package, module, and dependency.
  2. Create a new Go module with go mod init.
  3. Add dependencies by importing packages and running go mod tidy.
  4. Add or change an explicit dependency version with go get.
  5. Read and interpret go.mod.
  6. Explain the purpose of go.sum.
  7. Distinguish direct and indirect dependencies.
  8. Inspect the selected module graph.
  9. Discover available dependency versions.
  10. Upgrade and downgrade a dependency safely.
  11. Remove unused dependencies with go mod tidy.
  12. Download and verify module dependencies.
  13. Inspect Go module environment settings such as GOPROXY, GOSUMDB, GOPRIVATE, and GOMODCACHE.
  14. Build using vendored dependencies.
  15. Understand how private modules are configured.
  16. Apply a production-ready dependency workflow before committing code.

1. Prerequisites

You need:

  • Go installed.
  • A terminal or command prompt.
  • A text editor or IDE.
  • Internet access for downloading public Go modules.
  • Git is recommended, but not required for the core exercises.

The core module commands in this lab are suitable for modern module-aware Go releases. If your environment is managed by your organization, keep its proxy and private-module settings instead of overwriting them.


2. Lab Mental Model

Before starting, keep these terms clear.

Package

A package is a directory of Go source files compiled together.

Example import:

import "github.com/google/uuid"

Here, your program imports the uuid package.

Module

A module is a collection of related Go packages that are versioned together.

A module is identified by a module path in a go.mod file.

Example:

module example.com/order-service

Dependency

A dependency is another module or package your code requires.

Your project can depend on a package directly, while that package's module may itself depend on other modules.

Module root

The directory containing go.mod is the module root.

A simple project might look like this:

order-service/
├── go.mod
├── go.sum
└── main.go

3. Preflight Check

Open a terminal.

Run:

go version

Example output:

go version go1.xx.x linux/amd64

Your exact Go version and operating system will differ.

Now inspect the Go environment:

go env

You do not need to understand every value yet.

Check a few module-related settings specifically:

go env GOMOD GOPATH GOMODCACHE GOPROXY GOSUMDB GOPRIVATE

What to notice

  • GOMOD — path to the active go.mod, if you are inside a module.
  • GOPATH — Go workspace/cache base location.
  • GOMODCACHE — location where downloaded modules are cached.
  • GOPROXY — where Go looks for modules.
  • GOSUMDB — checksum database configuration for public modules.
  • GOPRIVATE — module-path patterns treated as private.

At this point, GOMOD may point to a null-device path or indicate that no module is active. That is expected if you are not inside a Go module yet.


4. Create the Lab Project

Create a project directory:

mkdir order-service
cd order-service

Confirm your current directory:

pwd

On Windows PowerShell, you can use:

Get-Location

5. Initialize a Go Module

Run:

go mod init example.com/order-service

Expected result resembles:

go: creating new go.mod: module example.com/order-service

List the files:

ls

Windows PowerShell:

Get-ChildItem

You should see:

go.mod

Open go.mod.

It should resemble:

module example.com/order-service

go 1.xx.x

The exact go directive is based on the Go toolchain used when the module is initialized.

Checkpoint 1

Answer these questions before continuing:

  1. What is the module path?
  2. Where is the module root?
  3. Does go.sum exist yet?
  4. Why might go.sum not exist yet?

Expected understanding

There are no external dependencies yet, so there may be nothing for Go to record in go.sum.


6. Create a Program with No External Dependencies

Create main.go:

package main

import "fmt"

func main() {
	fmt.Println("Order service started")
}

Run it:

go run .

Expected output:

Order service started

Build it:

go build .

Run tests across all packages:

go test ./...

Because we have not written tests, the result may resemble:

?    example.com/order-service    [no test files]

Key observation

fmt is part of the Go standard library. It does not become an external requirement in go.mod.


7. Add Your First External Dependency

We will use github.com/google/uuid to generate order IDs.

Replace main.go with:

package main

import (
	"fmt"

	"github.com/google/uuid"
)

func main() {
	orderID := uuid.New()
	fmt.Println("Order ID:", orderID)
}

At this moment, the source imports a package that is not yet recorded as a module requirement.

Try:

go run .

Depending on your Go version and module state, Go may tell you which package requirement is missing and suggest a command to add it.

Now deliberately synchronize dependencies with the source code:

go mod tidy

Then run:

go run .

Expected output resembles:

Order ID: 2d4b0d2b-....

The UUID will be different each time.


8. Inspect go.mod

Open go.mod again.

You should now see a requirement for the UUID module, similar to:

module example.com/order-service

go 1.xx.x

require github.com/google/uuid v1.6.0

The exact selected version is determined by the module resolution process and may differ if a newer compatible version exists when you run the lab.

What happened?

go mod tidy examined the packages imported by your module and made go.mod consistent with your source code.

It can:

  • add requirements that are needed but missing;
  • remove requirements that are no longer needed;
  • update go.sum entries required by the resulting dependency graph.

Checkpoint 2

Run:

go list -m

Expected output:

example.com/order-service

Now run:

go list -m all

You should see your main module and its selected dependencies.


9. Inspect go.sum

List the files:

ls

You should now have something similar to:

go.mod
go.sum
main.go

Open go.sum.

You will see checksum entries resembling:

github.com/google/uuid v1.6.0 h1:...
github.com/google/uuid v1.6.0/go.mod h1:...

What go.sum does

go.sum records cryptographic hashes used by the Go toolchain when authenticating downloaded module content.

Important rules

  • Commit go.sum to version control for normal applications and services.
  • Do not treat it as a lock file in the exact sense used by some other ecosystems.
  • Do not manually edit checksum lines.
  • Let Go commands maintain it.

10. Add a Dependency Explicitly with go get

There are two common workflows:

Workflow A — import first, then synchronize

Add import in source
        ↓
go mod tidy
        ↓
go.mod / go.sum updated

Workflow B — request a dependency/version explicitly

go get module@version
        ↓
go.mod / go.sum updated
        ↓
Import and use the package

Use go get when you intentionally want to add, upgrade, or downgrade a module requirement.

For example, pin UUID explicitly:

go get github.com/google/uuid@v1.6.0

Then inspect:

go list -m github.com/google/uuid

Expected output:

github.com/google/uuid v1.6.0

Run:

go mod tidy

Then verify the program still works:

go test ./...
go run .

11. Discover Available Versions

Ask Go which tagged versions it knows about:

go list -m -versions github.com/google/uuid

Output will list available versions, for example:

github.com/google/uuid v1.0.0 ... v1.5.0 v1.6.0

Why this matters

Do not blindly guess dependency versions.

Before changing a dependency, you can inspect available versions and intentionally select one.


12. Experience a Dependency Downgrade

Change UUID to an older known version:

go get github.com/google/uuid@v1.5.0

Inspect the selected version:

go list -m github.com/google/uuid

Expected:

github.com/google/uuid v1.5.0

Inspect go.mod.

You should see the changed version.

Now test the application:

go test ./...
go run .

If the code still works, the older version remains API-compatible with what this program uses.

Lesson

A successful module downgrade does not automatically prove the application is correct. Always run tests and relevant integration checks after dependency changes.


13. Upgrade the Dependency Again

Return to version v1.6.0:

go get github.com/google/uuid@v1.6.0

Confirm:

go list -m github.com/google/uuid

Run validation:

go mod tidy
go test ./...
go run .

Production habit

A safe version-change loop is:

Choose version
     ↓
go get module@version
     ↓
go mod tidy
     ↓
go test ./...
     ↓
Review go.mod + go.sum diff
     ↓
Commit

Inspect available upgrades before changing anything

You can ask Go to report newer versions for modules in the current build list:

go list -m -u all

This is useful for review because it separates discovering upgrades from applying upgrades.

Upgrade deliberately

To move one module to its latest available version:

go get github.com/google/uuid@latest

For production work, targeted upgrades are usually easier to review than changing the entire graph at once. Broad commands such as:

go get -u ./...

can update multiple modules that provide packages used by your project. Use broad upgrades only when you intend to review and test the larger change.

Minimal Version Selection — the key idea

Go builds a selected module list from the requirements in the module graph. If multiple parts of the graph require different versions of the same module path, Go's Minimal Version Selection (MVS) algorithm selects a version that satisfies the graph's requirements rather than relying on a traditional lock-file solver.

This is one reason go.mod, the dependency graph, and tests all matter during an upgrade.


14. Add a Dependency with Transitive Dependencies

So far, UUID is a very small dependency. We will now add a library that commonly brings additional module requirements so you can observe direct and indirect dependencies.

Run:

go get github.com/spf13/cobra@v1.8.1

Replace main.go with:

package main

import (
	"fmt"
	"os"

	"github.com/google/uuid"
	"github.com/spf13/cobra"
)

func main() {
	rootCmd := &cobra.Command{
		Use:   "orders",
		Short: "Generate a new order ID",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Order ID:", uuid.New())
		},
	}

	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

Synchronize:

go mod tidy

Run:

go run .

Try help output:

go run . --help

15. Direct vs. Indirect Dependencies

Inspect go.mod.

It may now resemble:

module example.com/order-service

go 1.xx.x

require (
	github.com/google/uuid v1.6.0
	github.com/spf13/cobra v1.8.1
)

require (
	// additional modules may appear here with // indirect
)

The exact transitive modules can change with dependency versions.

Direct dependency

A module is a direct dependency when your module directly imports one or more packages provided by that module.

In this lab:

github.com/google/uuid
github.com/spf13/cobra

are direct dependencies because main.go imports them.

Indirect dependency

An indirect dependency is needed by the module graph even though your own source does not directly import a package from that module.

Go may annotate such requirements with:

// indirect

Inspect all selected modules

Run:

go list -m all

Observe that the module graph may contain more modules than the two packages your code directly imports.


16. Ask Go Why a Dependency Exists

Use go mod why to understand why a module is needed.

For Cobra:

go mod why -m github.com/spf13/cobra

For UUID:

go mod why -m github.com/google/uuid

For an indirect module listed in your go.mod, substitute its module path:

go mod why -m MODULE_PATH

Example pattern:

# github.com/spf13/cobra
example.com/order-service
github.com/spf13/cobra

Your exact output can differ.

Key question

Can you trace a path from your application to the indirect dependency?


17. Inspect the Module Graph

Run:

go mod graph

You will see lines resembling:

moduleA moduleB@version

Each line means the module on the left has a requirement relationship involving the module on the right.

For a large real-world project, this graph can be extensive.

Challenge

Find:

  1. Your main module.
  2. Cobra.
  3. UUID.
  4. At least one transitive module.

18. Experience go mod tidy Removing an Unused Requirement

Add a dependency that your source code does not use:

go get github.com/pkg/errors@v0.9.1

Confirm it appears in the module information:

go list -m all

Now run:

go mod tidy

Check again:

go list -m all

Inspect go.mod.

If no package in your module needs github.com/pkg/errors, go mod tidy should remove the unnecessary requirement from the dependency graph described by your module files.

Lesson

go get can intentionally change a dependency requirement, but go mod tidy reconciles module metadata with what the source and package graph actually require.


19. Download Dependencies Without Building

Run:

go mod download

This downloads modules needed by the module graph into the module cache without requiring you to run the application first.

This is useful in workflows such as:

  • CI build preparation;
  • container image layer caching;
  • prefetching dependencies;
  • reproducible build environments.

Inspect the cache location:

go env GOMODCACHE

Do not manually modify files inside the module cache.


20. Verify Downloaded Module Content

Run:

go mod verify

Expected successful output:

all modules verified

This checks downloaded module data against expected cryptographic hashes.

Important security idea

Dependency management is not only about version selection. It also includes validating that module content has not unexpectedly changed.


21. Observe the Module Cache

Print the module cache directory:

go env GOMODCACHE

You can list it if desired.

Linux/macOS example:

ls "$(go env GOMODCACHE)"

PowerShell example:

Get-ChildItem (go env GOMODCACHE)

Optional experiment: clear the module cache

Only do this if you understand that Go will need to download modules again. Avoid doing this unnecessarily on slow or restricted networks.

go clean -modcache

Then restore the dependencies:

go mod download

Verify again:

go mod verify

Run:

go test ./...

This demonstrates that the project can restore its dependencies from module metadata rather than relying permanently on one developer's local cache.


22. Understand GOPROXY

Check the current module proxy configuration:

go env GOPROXY

A common public configuration resembles:

https://proxy.golang.org,direct

Do not overwrite your organization's proxy configuration just to match this example.

What GOPROXY controls

Go can retrieve modules through configured module proxies and, depending on the setting, fall back to direct version-control access.

This improves dependency availability and can help organizations control how external code is retrieved.


23. Understand GOSUMDB

Check:

go env GOSUMDB

For public modules, Go can use a checksum database to help authenticate module content.

Production rule

Do not globally disable checksum verification simply to work around a private-module problem.

For private modules, configure the appropriate private-module settings instead.


24. Configure Private Module Paths Safely

Suppose your company hosts private modules under:

github.com/mycompany/*

You can tell Go that these module paths are private:

go env -w GOPRIVATE='github.com/mycompany/*'

Check the value:

go env GOPRIVATE

What GOPRIVATE means

It tells the Go command that matching module paths are private. Among other effects, it provides defaults that keep matching private module paths away from the public module proxy and public checksum database.

You still need valid authentication for the private Git or module server.

Restore the setting after the lab

If you changed GOPRIVATE only for this exercise, remove the value:

go env -u GOPRIVATE

If your machine already had an organization-specific GOPRIVATE value before the lab, restore that original value instead of unsetting it.


25. Major Versions and Module Paths

Go's module versioning has an important rule for major versions v2 and higher.

A module at major version 2+ normally includes the major version in its module path.

Conceptual example:

import "example.com/library/v2"

The /v2 is part of the import/module path, not just decoration.

This allows incompatible major versions to exist as distinct module paths.

Knowledge check

Which looks like a normal import path for version 3 of a module?

A. example.com/payments@v3
B. example.com/payments/v3
C. example.com/v3/payments

Answer: B


26. Optional Advanced Lab: Vendoring Dependencies

Vendoring creates a local vendor/ directory containing dependency source needed for builds.

Run:

go mod vendor

Inspect the project:

order-service/
├── go.mod
├── go.sum
├── main.go
└── vendor/

Inspect vendor metadata:

cat vendor/modules.txt

PowerShell:

Get-Content vendor/modules.txt

Build explicitly from vendored dependencies:

go build -mod=vendor .

Run tests using the vendor directory:

go test -mod=vendor ./...

When might vendoring be useful?

Examples include:

  • highly controlled build environments;
  • environments where dependency source must be checked into the repository;
  • certain offline or restricted-network build processes;
  • compliance or source-review workflows.

Vendoring is optional. Go Modules do not require every project to commit a vendor/ directory.

Remove the vendor directory after this optional exercise

Linux/macOS:

rm -rf vendor

PowerShell:

Remove-Item -Recurse -Force vendor

27. Optional Advanced Lab: Local Development with replace

The replace directive is useful when you need your main module to temporarily use a local module during development.

Move to the directory containing order-service:

cd ..

Create another module:

mkdir greeting-lib
cd greeting-lib
go mod init example.com/greeting-lib

Create greeting.go:

package greeting

func Message() string {
	return "Dependency loaded from local module"
}

Return to the application:

cd ../order-service

Add a local replacement:

go mod edit -replace=example.com/greeting-lib=../greeting-lib

Add an explicit local-only requirement:

go mod edit -require=example.com/greeting-lib@v0.0.0

The placeholder version works here because the replace directive tells Go to use the local directory instead of resolving that module version from a remote repository.

Now modify main.go:

package main

import (
	"fmt"
	"os"

	"example.com/greeting-lib"
	"github.com/google/uuid"
	"github.com/spf13/cobra"
)

func main() {
	rootCmd := &cobra.Command{
		Use:   "orders",
		Short: "Generate a new order ID",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println(greeting.Message())
			fmt.Println("Order ID:", uuid.New())
		},
	}

	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

Run:

go mod tidy
go run .

Expected output includes:

Dependency loaded from local module
Order ID: ...

Inspect go.mod.

You should see a replace directive similar to:

replace example.com/greeting-lib => ../greeting-lib

Why replace is useful

It lets you test a local dependency without publishing a new remote version first.

Production caution

A local filesystem replace path usually should not be left in a release-oriented go.mod accidentally. Review replace directives before merging or releasing.

Remove the local dependency after the exercise

First restore main.go to the Cobra + UUID version from Section 14.

Then run:

go mod edit -dropreplace=example.com/greeting-lib
go mod tidy

Confirm:

go test ./...

28. Inspect Useful Module Commands

Use this command table as a reference.

Command Purpose
go mod init <module-path> Initialize a module
go mod tidy Synchronize go.mod and go.sum with source requirements
go get module@version Add, upgrade, or downgrade a module requirement
go list -m Show the main module
go list -m all Show all selected modules in the build list
go list -m -versions module Show known tagged versions
go mod why -m module Explain why a module is needed
go mod graph Print module requirement relationships
go mod download Download modules into the module cache
go mod verify Verify downloaded module content
go mod vendor Create a vendor directory
go mod edit Programmatically edit go.mod directives
go env GOMOD Show the active go.mod path
go env GOMODCACHE Show module cache location
go env GOPROXY Show module proxy configuration
go env GOPRIVATE Show private-module patterns
go test ./... Test all packages in the module
go build ./... Build all packages in the module

29. What Not to Do

Avoid these dependency-management mistakes.

Mistake 1 — Manually editing go.sum

Let Go manage checksum entries.

Mistake 2 — Upgrading everything without testing

A command that changes many dependencies can introduce behavioral changes even if compilation succeeds.

Mistake 3 — Ignoring go.mod or go.sum changes in code review

Dependency changes are code changes and should be reviewed.

Mistake 4 — Leaving unused requirements

Run:

go mod tidy

before committing.

Mistake 5 — Disabling security checks globally to fix one private repository

Use properly scoped private-module configuration and correct repository authentication.

Mistake 6 — Forgetting that v2+ can change the module path

Major-version import paths matter.

Mistake 7 — Assuming the newest version is automatically the safest choice

Review release notes, compatibility, tests, and security impact before upgrading production dependencies.


30. Production-Ready Dependency Workflow

Use this workflow when adding a dependency to a real project.

Step 1 — Justify the dependency

Ask:

  • Do we really need it?
  • Can the standard library solve the problem?
  • Is the dependency actively maintained?
  • Is its license acceptable for the project?
  • Is the dependency footprint reasonable?

Step 2 — Add or import it intentionally

Example:

go get github.com/google/uuid@v1.6.0

Step 3 — Synchronize module metadata

go mod tidy

Step 4 — Format and validate source

go fmt ./...
go vet ./...
go test ./...

Step 5 — Build

go build ./...

Step 6 — Inspect the graph

go list -m all

For unexpected modules:

go mod why -m MODULE_PATH

Step 7 — Verify downloaded dependencies

go mod verify

Step 8 — Optional vulnerability check

For a stronger production workflow, install Go's vulnerability scanner as a command:

go install golang.org/x/vuln/cmd/govulncheck@latest

Then run it from the module root:

govulncheck ./...

Notice the command choice: use go install ...@version to install an executable. Use go get to change dependencies recorded for the current module. Installing a command with a version suffix does not add that command to this application's go.mod.

Treat vulnerability findings as dependency-review input: determine whether the vulnerable code is reachable, identify the fixed dependency version, upgrade deliberately, and rerun tests.

Step 9 — Review changes

Review at minimum:

go.mod
go.sum

If Git is available:

git diff -- go.mod go.sum

Step 10 — Commit module metadata

Normally commit both:

go.mod
go.sum

along with the source change that required the dependency.


31. Final Validation

From the order-service module root, run:

go mod tidy
go mod verify
go vet ./...
go test ./...
go build ./...
go run . --help

Then inspect:

go list -m all

Your project should be clean, buildable, and have dependency metadata that matches its source code.


32. Troubleshooting Guide

Error: go.mod file not found

Cause

You are outside the module root and its parent hierarchy.

Fix

Move into the project:

cd order-service

Confirm:

go env GOMOD

Error: no required module provides package ...

Cause

Your source imports a package that is not currently provided by the module build list.

Fix

If the import is intended:

go mod tidy

Or explicitly request a version:

go get MODULE_PATH@VERSION

Error: authentication failure for a private repository

Cause

The module may be private, but your Git/VCS credentials or private-module settings are incomplete.

Check

go env GOPRIVATE GOPROXY GONOPROXY GONOSUMDB

Then verify that your Git client can authenticate to the private repository.


Error: checksum mismatch

Meaning

Treat checksum mismatches as security-sensitive. Do not casually bypass verification.

Action

Investigate whether:

  • a dependency was republished incorrectly;
  • a proxy/cache is serving unexpected content;
  • the local module cache is corrupted;
  • module metadata was modified incorrectly.

Do not solve a public-module checksum mismatch by globally disabling verification.


go mod tidy changed more than expected

Use:

git diff -- go.mod go.sum

Then investigate unexpected dependency changes with:

go list -m all
go mod why -m MODULE_PATH

33. Student Challenges

Complete these without copying commands from previous sections if possible.

Challenge 1 — Add a new dependency

Choose a small public Go package.

Tasks:

  1. Add an import.
  2. Run the appropriate module command.
  3. Confirm the module appears in go.mod.
  4. Run the application.
  5. Run go mod tidy.

Challenge 2 — Pin a version

  1. List available versions of the module.
  2. Select a specific version.
  3. Update to that version.
  4. Confirm the selected version.
  5. Run tests.

Useful command pattern:

go list -m -versions MODULE_PATH
go get MODULE_PATH@VERSION
go list -m MODULE_PATH

Challenge 3 — Explain an indirect dependency

  1. Find a module marked // indirect.
  2. Run go mod why -m on it.
  3. Explain in one sentence why your application needs it.

Challenge 4 — Remove an unused dependency

  1. Add a module requirement.
  2. Do not import its package.
  3. Run go mod tidy.
  4. Confirm the unused requirement disappears if nothing else needs it.

Challenge 5 — Rebuild from dependency metadata

  1. Ensure go.mod and go.sum are present.
  2. Download dependencies.
  3. Verify them.
  4. Test the module.
  5. Build the module.

Commands:

go mod download
go mod verify
go test ./...
go build ./...

34. Knowledge Check

Question 1

Which file defines the module path and dependency requirements?

A. go.yaml
B. go.mod
C. go.lock
D. modules.json

Answer: B


Question 2

Which command synchronizes dependency requirements with imported packages?

A. go mod tidy
B. go clean
C. go fmt
D. go env

Answer: A


Question 3

Which command intentionally selects a specific module version?

go get example.com/library@v1.2.3

Answer: go get with an explicit version query.


Question 4

Should go.sum normally be committed for an application/service?

Answer: Yes.


Question 5

What does // indirect mean?

Answer: The module is required by the selected module/package graph even though the main module does not directly import a package from that module in the relevant direct-dependency sense.


Question 6

Which command helps answer, "Why is this module in my dependency graph?"

Answer:

go mod why -m MODULE_PATH

Question 7

Which command checks downloaded modules against expected hashes?

Answer:

go mod verify

Question 8

What should be reviewed after an upgrade?

Answer: At minimum, source behavior, tests, go.mod, go.sum, and the resulting dependency graph; production teams may also review release notes, licenses, and security impact.


35. Lab Completion Checklist

You have completed the lab when you can check every item below.

  • I installed and verified Go with go version.
  • I created a new module with go mod init.
  • I can explain the module path in go.mod.
  • I added an external dependency.
  • I generated and inspected go.sum.
  • I used go mod tidy.
  • I used go get with an explicit version.
  • I listed available module versions.
  • I downgraded and upgraded a dependency.
  • I inspected all selected modules with go list -m all.
  • I identified direct and indirect dependencies.
  • I used go mod why -m.
  • I inspected go mod graph.
  • I downloaded dependencies with go mod download.
  • I verified dependencies with go mod verify.
  • I inspected GOMODCACHE.
  • I inspected GOPROXY and GOSUMDB.
  • I understand when GOPRIVATE is needed.
  • I understand the /v2, /v3, etc. major-version path rule.
  • I tested and built the module successfully.
  • I know that go.mod and go.sum should normally be reviewed and committed.

36. Final Takeaway

Go Modules provide a complete dependency-management system built directly into the Go toolchain.

The core workflow to remember is:

Write/import code
      ↓
go get module@version      ← when intentionally choosing/changing a version
      ↓
go mod tidy                ← synchronize dependency metadata
      ↓
go test ./...
      ↓
go build ./...
      ↓
go mod verify
      ↓
Review go.mod + go.sum
      ↓
Commit

If you remember only five commands, remember these:

go mod init example.com/project
go get MODULE@VERSION
go mod tidy
go list -m all
go mod verify

That workflow gives you clean dependency metadata, repeatable module resolution, explicit version control, and a strong foundation for production Go builds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment