Go Modules become much easier once you keep one mental model in mind:
Your Go source code says what packages you use.
go.modsays which modules/versions provide them.go.sumhelps verify downloaded dependency content.
A module is normally your Go project or library together with its dependency information. go mod init creates the module’s go.mod file, while commands such as go get and go mod tidy keep dependency information synchronized with your source code. (Go.dev)
1. What is dependency management?
Suppose your program needs to generate a UUID.
You could write all the UUID logic yourself, or use an existing Go package:
import "github.com/google/uuid"
Now your application depends on code from another project.
That external code is a dependency.
Go Modules manage:
Your application
|
| imports
v
github.com/google/uuid
|
| particular version
v
v1.6.0
The version of that dependency is recorded in your project’s go.mod.
2. What / Why / When / How / Where
| Question | Simple answer |
|---|---|
| What? | Go Modules are Go’s dependency-management system. |
| Why? | To track external libraries and their versions reliably. |
| When? | For practically every normal Go project that contains packages or external dependencies. |
| How? | Start with go mod init, add/use dependencies, and maintain them with commands such as go get and go mod tidy. |
| Where? | Dependency information lives mainly in go.mod and go.sum at the module root. |
3. The three things to remember
Think of a Go project like this:
go-mod-demo/
│
├── go.mod
├── go.sum
└── main.go
main.go
Your actual Go source code.
go.mod
Describes your module and records required module versions. (Go.dev)
Example:
module example.com/go-mod-demo
go 1.xx
require github.com/google/uuid v1.6.0
Don’t worry about the exact go version shown there; Go writes the appropriate value for your environment.
go.sum
Contains cryptographic hashes associated with downloaded module dependencies so Go can verify dependency content. (Go.dev)
You normally do not manually edit go.sum.
4. Complete example — UUID generator
This is the only example you need for understanding the basic workflow.
We will build:
Go Program
|
| import
v
github.com/google/uuid
|
v
Generate UUID
The example uses github.com/google/uuid version v1.6.0. That version provides uuid.NewString(). (Chromium Git Repositories)
Step 1 — Create the project
mkdir go-mod-demo
cd go-mod-demo
Step 2 — Initialize a Go module
Run:
go mod init example.com/go-mod-demo
You should now have:
go-mod-demo/
└── go.mod
The command:
go mod init example.com/go-mod-demo
means:
go mod init
│ │ │
│ │ └── Name/path of our module
│ │
│ └────── Initialize
│
└────────── Go command
go mod init creates a new go.mod in the current directory and establishes that directory as the module root. (Go.dev)
Step 3 — Create main.go
Create this file:
package main
import (
"fmt"
// This package comes from an external Go module.
"github.com/google/uuid"
)
func main() {
// uuid.NewString() comes from the external dependency.
id := uuid.NewString()
fmt.Println("Generated UUID:", id)
}
That’s the complete application.
Notice this line:
"github.com/google/uuid"
Your application is saying:
“I need the
uuidpackage.”
But Go still needs to know which module version should provide it.
Step 4 — Add the dependency
Run:
go get github.com/google/uuid@v1.6.0
Now look at your folder:
go-mod-demo/
│
├── go.mod
├── go.sum
└── main.go
And go.mod will contain a requirement for the dependency:
require github.com/google/uuid v1.6.0
The important connection is:
main.go
|
| import "github.com/google/uuid"
|
v
go.mod
|
| require github.com/google/uuid v1.6.0
|
v
Go downloads dependency
go get is one of Go’s standard ways to add or change a dependency version recorded for the module. (Go.dev)
Step 5 — Run the application
go run .
Example output:
Generated UUID: 550e8400-e29b-41d4-a716-446655440000
Your actual UUID will be different.
You have now successfully used an external Go dependency.
Step 6 — Clean the dependencies
Run:
go mod tidy
This is a very useful command.
It essentially asks Go:
“Look at my source code and make sure
go.modandgo.summatch what the project really needs.”
go mod tidy adds missing module requirements, removes requirements that are no longer needed, and updates relevant go.sum entries. (Go.dev)
A good habit is:
go mod tidy
after adding or removing imports.
5. The complete workflow
flowchart TD
A["Create Project"] --> B["go mod init"]
B --> C["go.mod created"]
C --> D["Write Go code"]
D --> E["Import external package"]
E --> F["go get dependency@version"]
F --> G["go.mod / go.sum updated"]
G --> H["go run ."]
H --> I["go mod tidy"]
Or remember it simply as:
CREATE PROJECT
↓
go mod init
↓
WRITE CODE
↓
import dependency
↓
go get dependency
↓
go run .
↓
go mod tidy
6. Understanding go.mod
Your file might conceptually look like:
module example.com/go-mod-demo
go 1.xx
require github.com/google/uuid v1.6.0
Let’s decode it.
module
module example.com/go-mod-demo
This is the identity/path of your module.
Think:
module = my project's module name
go
go 1.xx
This records the Go language/module compatibility version associated with the module.
For now, let the Go tools manage it.
require
require github.com/google/uuid v1.6.0
Means:
My project requires
github.com/google/uuid
at selected version
v1.6.0
7. Module vs Package
This distinction confuses many Go beginners.
They are not the same thing.
| Module | Package |
|---|---|
| Collection of one or more related Go packages | Go source code in a directory |
Has a go.mod at its root | Declared with package xyz |
| Used for dependency/version management | Used for organizing and importing Go code |
Example: github.com/google/uuid module | Example: the uuid package you import |
Simple mental model:
Module
│
├── Package A
├── Package B
└── Package C
A dependency is normally managed at the module level, even though your code imports packages.
8. go.mod vs go.sum
go.mod | go.sum |
|---|---|
| Describes your module | Contains dependency verification hashes |
| Records required module versions | Helps verify downloaded module content |
| Human-readable dependency configuration | Mostly maintained automatically |
| Important to commit to Git | Normally committed to Git too |
Think:
go.mod
"What dependencies should I use?"
go.sum
"Can I verify the dependency content I downloaded?"
9. Important commands compared
| Command | Purpose | When you use it |
|---|---|---|
go mod init | Create a new module | At project creation |
go get package@version | Add/change a dependency | When adding or changing dependencies |
go mod tidy | Synchronize dependency files with source code | After dependency/import changes |
go run . | Compile and run the current package | During development |
go build | Compile your project | When you want a binary/build check |
The three module commands worth memorizing first are:
go mod init
go get
go mod tidy
Everything else can come later.
10. What happens if you remove the dependency?
Suppose you change main.go to:
package main
import "fmt"
func main() {
fmt.Println("Hello")
}
There is no longer:
import "github.com/google/uuid"
Run:
go mod tidy
Go sees:
Source code
|
X no UUID import
|
go.mod
and can remove the now-unneeded UUID module requirement. This source-driven synchronization is exactly what go mod tidy is designed to do. (Go.dev)
11. Direct vs indirect dependencies
You may eventually see:
require (
github.com/google/uuid v1.6.0
example.com/something v1.2.3 // indirect
)
Don’t let this confuse you.
Direct
Your code directly imports it:
import "github.com/google/uuid"
YOUR PROGRAM
↓
UUID
Indirect
Your dependency needs another module:
YOUR PROGRAM
↓
Dependency A
↓
Dependency B
Dependency B can appear as:
// indirect
An indirect requirement indicates that the main module does not directly import a package from that module, though it is needed through the dependency graph. (Go.dev)
For now:
Don’t manually manage
// indirect. Let Go do it.
12. One golden rule
Don’t think:
“I need to manually maintain a big dependency file.”
Instead think:
Write imports
↓
Go examines your code
↓
Go manages module requirements
↓
go.mod + go.sum
Use the Go commands instead of manually editing dependency information unless you have a specific reason to do otherwise. The official Go documentation also recommends managing dependencies through Go commands so that go.mod stays consistent. (Go.dev)
13. Your everyday workflow
For a new project:
mkdir myapp
cd myapp
go mod init example.com/myapp
Write code.
If you need a dependency:
go get dependency@version
Then:
go run .
And periodically:
go mod tidy
That’s enough for learning Go Modules initially.
14. Final cheat sheet
| You want to… | Use |
|---|---|
| Start dependency management | go mod init |
| Add/change a dependency | go get |
| Clean dependency information | go mod tidy |
| See your dependencies | Open go.mod |
| Understand integrity information | Look at go.sum |
| Use a dependency in code | import "..." |
| Run the program | go run . |
Remember this sentence
main.gouses packages →go.modtracks required modules/versions →go.sumhelps verify downloaded dependency content →go mod tidykeeps everything synchronized.
If that sentence makes sense, you understand the core of dependency management using Go Modules. (Go.dev)