Go Modules — Dependency Management with go mod and Module Versioning
In this tutorial, you will learn about Go Modules. We cover key concepts, practical examples, and best practices to help you master this topic.
Go modules manage dependencies with go.mod and go.sum files, semantic versioning, and version selection for reproducible builds.
What You'll Learn
- Creating and initializing modules
- Adding and managing dependencies
- Version selection and upgrades
- Module proxies and vendoring
Why It Matters
Modules ensure reproducible builds. Docker uses modules for dependency management. Kubernetes manages hundreds of module dependencies. DodaZIP uses modules for reproducible builds.
Real-World Use
Library development, application dependency management, CI/CD reproducibility, multi-module projects.
flowchart LR
A["Modules"] --> B["go.mod"]
A --> C["go.sum"]
A --> D["Dependencies"]
A --> E["Versioning"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Creating a Module
go mod init github.com/user/myapp
// go.mod
module github.com/user/myapp
go 1.22
require (
github.com/gorilla/mux v1.8.1
github.com/lib/pq v1.10.9
)
Adding Dependencies
# Add a new dependency
go get github.com/gorilla/mux
# Add specific version
go get github.com/gorilla/mux@v1.8.0
# Upgrade all dependencies
go get -u ./...
# Remove unused dependencies
go mod tidy
Upgrading
# Check available upgrades
go list -u -m all
# Upgrade major version
go get github.com/foo/v2
# Upgrade specific module
go get -u github.com/gorilla/mux
go.sum File
github.com/gorilla/mux v1.8.1 h1:TuMoUvkRETdXqU+3a7mWsnM1G6+3MKG0gZ3q7D4D4c=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
Major Versions
// Module v2 path
module github.com/user/myapp/v2
// Import
import "github.com/user/myapp/v2/pkg/helper"
Vendoring
go mod vendor
# Build with vendored dependencies
go build -mod=vendor ./...
Common Mistakes
1. Not Running go mod tidy
Always run go mod tidy after adding/removing dependencies. It cleans up go.mod and go.sum.
2. Committing go.sum Without go.mod
Both files must be committed. go.sum ensures reproducible builds.
3. Using master/main Branches
// Bad: go get github.com/foo@main
// Good: Use release tags go get github.com/foo@v1.2.3
4. Ignoring Indirect Dependencies
go mod tidy manages indirect deps automatically. Don't manually add them.
5. Not Using Module Path Convention
Module path should match the repo URL for go get to work.
Practice Questions
1. What does go.mod contain? Module name, Go version, and dependency requirements with versions.
2. What is the purpose of go.sum? Cryptographic hashes of module content. Ensures downloads match expected content.
3. What does go mod tidy do? Adds missing deps, removes unused ones, and updates go.sum. Run after changing imports.
4. How do major versions work? v2+ modules have a /v2 suffix in module path. Go treats them as different modules.
Challenge: Resolve a dependency conflict where two modules require different versions of the same dependency.
Solution
# Check current versions
go list -m all | grep conflicting-mod
# Upgrade one module to match
go get other-module@latest
# Or use replace directive in go.mod
replace conflicting-mod v1.0.0 => conflicting-mod v1.1.0
# Clean up
go mod tidy
FAQ
{{< faq question="What is the minimum Go version for modules?" >}} Go 1.11+ supports modules (experimental). Go 1.16+ has modules enabled by default and is the minimum recommended version. {{< /faq >}}
{{< faq question="Should I vendor dependencies?" >}} No for most projects. Vendoring is for enterprise environments with air-gapped builds or audit requirements. {{< /faq >}}
{{< faq question="How does Go resolve dependencies?" >}} Minimum Version Selection (MVS). Uses the minimum version required by any dependency. More conservative than npm's semver range. {{< /faq >}}
{{< faq question="What is a module proxy?" >}} A cache for module downloads. Default is proxy.golang.org. Set GOPROXY=direct to bypass. Use for faster, reliable CI builds. {{< /faq >}}
{{< faq question="Can I have multiple modules in one repo?" >}} Yes, using different go.mod files in subdirectories. Common for monorepos with multiple libraries. {{< /faq >}}
Try It Yourself
mkdir mymodule && cd mymodule
go mod init example.com/mymodule
cat > main.go << 'EOF'
package main
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Go())
}
EOF
go mod tidy
go run main.go
Expected output:
Don't communicate by sharing memory, share memory by communicating.
What's Next
Now that you understand modules, explore building CLI applications in Go.
| Topic | Description | Link |
|---|---|---|
| Go CLI Apps | Building CLI tools | {{< ref "39-cli-apps" >}} |
| Go Web Frameworks | Web frameworks | {{< ref "40-web-frameworks" >}} |
| Go Deployment | Deploying Go apps | {{< ref "43-deployment" >}} |