Go Modules & Workspaces

Go modules and workspaces for dependency management. Essential commands for Go project management.


Initialization

1# Initialize new module
2go mod init example.com/myproject
3go mod init github.com/username/repo
4
5# Initialize in existing directory
6cd myproject
7go mod init example.com/myproject

go.mod file:

 1module example.com/myproject
 2
 3go 1.21
 4
 5require (
 6    github.com/gin-gonic/gin v1.9.1
 7    github.com/lib/pq v1.10.9
 8)
 9
10require (
11    // Indirect dependencies
12    github.com/bytedance/sonic v1.9.1 // indirect
13    github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
14)

Adding Dependencies

 1# Add dependency (automatically adds to go.mod)
 2go get github.com/gin-gonic/gin
 3
 4# Add specific version
 5go get github.com/gin-gonic/gin@v1.9.1
 6
 7# Add latest version
 8go get github.com/gin-gonic/gin@latest
 9
10# Add specific commit
11go get github.com/gin-gonic/gin@abc1234
12
13# Add branch
14go get github.com/gin-gonic/gin@master
15
16# Add and install
17go get -u github.com/gin-gonic/gin  # Update to latest minor/patch
18go get -u=patch github.com/gin-gonic/gin  # Update to latest patch only

Removing Dependencies

1# Remove unused dependencies
2go mod tidy
3
4# Remove specific dependency (edit go.mod, then tidy)
5# Remove from go.mod manually, then:
6go mod tidy

Updating Dependencies

 1# Update all dependencies to latest minor/patch
 2go get -u ./...
 3
 4# Update all dependencies to latest patch only
 5go get -u=patch ./...
 6
 7# Update specific package
 8go get -u github.com/gin-gonic/gin
 9
10# View available updates
11go list -u -m all
12
13# Update to specific version
14go get github.com/gin-gonic/gin@v1.10.0

Listing Dependencies

 1# List all dependencies
 2go list -m all
 3
 4# List direct dependencies only
 5go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all
 6
 7# List outdated dependencies
 8go list -u -m all
 9
10# Show dependency graph
11go mod graph
12
13# Show why a package is needed
14go mod why github.com/gin-gonic/gin
15
16# Show detailed info
17go list -m -json github.com/gin-gonic/gin

Vendoring

1# Create vendor directory
2go mod vendor
3
4# Build using vendor
5go build -mod=vendor
6
7# Verify vendor directory matches go.mod
8go mod verify

Use Cases:

  • Offline builds
  • Ensure reproducible builds
  • Corporate environments with restricted internet

Cleaning Up

 1# Remove unused dependencies and add missing ones
 2go mod tidy
 3
 4# Verify dependencies
 5go mod verify
 6
 7# Download dependencies to module cache
 8go mod download
 9
10# Clean module cache
11go clean -modcache

Replace Directive

Local Development:

1// go.mod
2module example.com/myproject
3
4go 1.21
5
6require github.com/myorg/shared v1.0.0
7
8// Replace with local version
9replace github.com/myorg/shared => ../shared

Fork or Mirror:

1// Replace with fork
2replace github.com/original/repo => github.com/myusername/repo v1.2.3
3
4// Replace with local path
5replace github.com/original/repo => /path/to/local/repo
1# Add replace directive
2go mod edit -replace github.com/original/repo=../local/repo
3
4# Remove replace directive
5go mod edit -dropreplace github.com/original/repo

Go Workspaces (Go 1.18+)

Creating Workspace

1# Initialize workspace
2go work init
3
4# Add modules to workspace
5go work use ./module1
6go work use ./module2
7
8# Add all modules in directory
9go work use ./...

go.work file:

 1go 1.21
 2
 3use (
 4    ./api
 5    ./shared
 6    ./worker
 7)
 8
 9// Optional: replace directives
10replace github.com/myorg/shared => ./shared

Workspace Structure

 1myproject/
 2β”œβ”€β”€ go.work           # Workspace file
 3β”œβ”€β”€ api/
 4β”‚   β”œβ”€β”€ go.mod
 5β”‚   β”œβ”€β”€ go.sum
 6β”‚   └── main.go
 7β”œβ”€β”€ shared/
 8β”‚   β”œβ”€β”€ go.mod
 9β”‚   β”œβ”€β”€ go.sum
10β”‚   └── lib.go
11└── worker/
12    β”œβ”€β”€ go.mod
13    β”œβ”€β”€ go.sum
14    └── main.go

Workspace Commands

 1# Sync workspace
 2go work sync
 3
 4# Edit workspace
 5go work edit -use ./newmodule
 6go work edit -dropuse ./oldmodule
 7
 8# Run commands in workspace context
 9go build ./...
10go test ./...
11
12# Disable workspace (use go.mod instead)
13go build -workfile=off

Private Modules

Setup for Private Repos

 1# Configure Git for private repos
 2git config --global url."git@github.com:".insteadOf "https://github.com/"
 3
 4# Set GOPRIVATE environment variable
 5export GOPRIVATE=github.com/myorg/*,gitlab.com/mycompany/*
 6
 7# Or in go env
 8go env -w GOPRIVATE=github.com/myorg/*
 9
10# Disable checksum database for private modules
11go env -w GONOSUMDB=github.com/myorg/*

Using Private Modules

1# Ensure SSH key is configured
2ssh -T git@github.com
3
4# Install private module
5go get github.com/myorg/private-repo

.netrc for HTTPS (alternative):

1machine github.com
2login username
3password ghp_xxxxxxxxxxxxx

Module Proxy

 1# View current proxy settings
 2go env GOPROXY
 3
 4# Set proxy
 5go env -w GOPROXY=https://proxy.golang.org,direct
 6
 7# Disable proxy (direct only)
 8go env -w GOPROXY=direct
 9
10# Use multiple proxies
11go env -w GOPROXY=https://proxy1.com,https://proxy2.com,direct
12
13# Bypass proxy for specific modules
14go env -w GOPRIVATE=github.com/myorg/*

Common go.mod Directives

 1module example.com/myproject
 2
 3// Go version
 4go 1.21
 5
 6// Direct dependencies
 7require (
 8    github.com/gin-gonic/gin v1.9.1
 9    github.com/lib/pq v1.10.9
10)
11
12// Indirect dependencies (automatically managed)
13require (
14    github.com/bytedance/sonic v1.9.1 // indirect
15)
16
17// Replace dependencies
18replace (
19    github.com/old/repo => github.com/new/repo v1.2.3
20    github.com/local/repo => ../local/repo
21)
22
23// Exclude specific versions
24exclude github.com/broken/package v1.2.3
25
26// Retract published versions (in your own module)
27retract (
28    v1.0.0 // Published accidentally
29    [v1.1.0, v1.2.0] // Range of versions
30)

Troubleshooting

Clear Module Cache

1# Clear entire module cache
2go clean -modcache
3
4# Clear build cache
5go clean -cache
6
7# Clear all caches
8go clean -cache -modcache -testcache

Fix Checksum Mismatch

1# Remove go.sum and regenerate
2rm go.sum
3go mod tidy
4
5# Or update specific module
6go get github.com/package/name@latest
7go mod tidy

Resolve Version Conflicts

1# View dependency graph
2go mod graph | grep package-name
3
4# See why package is required
5go mod why github.com/package/name
6
7# Force specific version
8go get github.com/package/name@v1.2.3
9go mod tidy

Private Repo Access Issues

 1# Check GOPRIVATE
 2go env GOPRIVATE
 3
 4# Test SSH access
 5ssh -T git@github.com
 6
 7# Use HTTPS with token
 8git config --global url."https://username:token@github.com/".insteadOf "https://github.com/"
 9
10# Or use .netrc file

Best Practices

1. Always Run go mod tidy

1# After adding/removing imports
2go mod tidy
3
4# Before committing
5go mod tidy
6git add go.mod go.sum
7git commit -m "Update dependencies"

2. Commit go.sum

1# βœ… Always commit go.sum
2git add go.mod go.sum
3git commit
4
5# ❌ Don't ignore go.sum
6# .gitignore should NOT contain go.sum

3. Use Semantic Versioning

1# Tag releases properly
2git tag v1.0.0
3git push origin v1.0.0
4
5# Follow semver
6v1.0.0  # Initial release
7v1.0.1  # Patch (bug fixes)
8v1.1.0  # Minor (new features, backward compatible)
9v2.0.0  # Major (breaking changes)

4. Pin Major Versions in Imports

1// For v2+ modules, include version in import path
2import "github.com/user/repo/v2"
3
4// go.mod
5module github.com/user/repo/v2
6
7go 1.21

5. Use Workspace for Monorepos

1# Instead of replace directives, use workspaces
2go work init
3go work use ./module1 ./module2 ./module3
4
5# Benefits:
6# - Cleaner go.mod files
7# - Easier to work across modules
8# - No need to remember to remove replace directives

Example Project Structure

Single Module

 1myproject/
 2β”œβ”€β”€ go.mod
 3β”œβ”€β”€ go.sum
 4β”œβ”€β”€ main.go
 5β”œβ”€β”€ internal/
 6β”‚   β”œβ”€β”€ handler/
 7β”‚   β”‚   └── handler.go
 8β”‚   └── service/
 9β”‚       └── service.go
10└── pkg/
11    └── utils/
12        └── utils.go

Multi-Module Workspace

 1myproject/
 2β”œβ”€β”€ go.work
 3β”œβ”€β”€ api/
 4β”‚   β”œβ”€β”€ go.mod
 5β”‚   β”œβ”€β”€ go.sum
 6β”‚   β”œβ”€β”€ main.go
 7β”‚   └── internal/
 8β”œβ”€β”€ shared/
 9β”‚   β”œβ”€β”€ go.mod
10β”‚   β”œβ”€β”€ go.sum
11β”‚   └── pkg/
12β”‚       β”œβ”€β”€ models/
13β”‚       └── utils/
14└── worker/
15    β”œβ”€β”€ go.mod
16    β”œβ”€β”€ go.sum
17    └── main.go

Quick Reference

 1# Initialize
 2go mod init <module-path>
 3
 4# Add/Update dependencies
 5go get <package>[@version]
 6go get -u ./...
 7
 8# Clean up
 9go mod tidy
10
11# Vendor
12go mod vendor
13
14# Workspace
15go work init
16go work use ./module
17
18# Info
19go list -m all
20go mod graph
21go mod why <package>
22
23# Cache
24go clean -modcache
25
26# Private repos
27go env -w GOPRIVATE=<pattern>

Create and Publish Go Module

Module Structure

 1mymodule/
 2β”œβ”€β”€ go.mod
 3β”œβ”€β”€ go.sum
 4β”œβ”€β”€ README.md
 5β”œβ”€β”€ LICENSE
 6β”œβ”€β”€ .gitignore
 7β”œβ”€β”€ cmd/
 8β”‚   └── myapp/
 9β”‚       └── main.go
10β”œβ”€β”€ pkg/
11β”‚   └── mylib/
12β”‚       β”œβ”€β”€ mylib.go
13β”‚       └── mylib_test.go
14└── internal/
15    └── helper/
16        └── helper.go

Initialize Module

1# Create module
2go mod init github.com/username/mymodule
3
4# Or with version
5go mod init github.com/username/mymodule/v2

go.mod

 1module github.com/username/mymodule
 2
 3go 1.21
 4
 5require (
 6    github.com/pkg/errors v0.9.1
 7    golang.org/x/sync v0.5.0
 8)
 9
10require (
11    // Indirect dependencies
12    github.com/stretchr/testify v1.8.4 // indirect
13)

Version Your Module

 1# Tag version
 2git tag v1.0.0
 3git push origin v1.0.0
 4
 5# Major version (v2+) requires module path change
 6# go.mod:
 7module github.com/username/mymodule/v2
 8
 9# Tag
10git tag v2.0.0
11git push origin v2.0.0

Publish to GitHub

 1# Push to GitHub
 2git init
 3git add .
 4git commit -m "Initial commit"
 5git remote add origin https://github.com/username/mymodule.git
 6git push -u origin main
 7
 8# Tag version
 9git tag v1.0.0
10git push origin v1.0.0
11
12# Module is now available!
13# Users can install with:
14# go get github.com/username/mymodule@v1.0.0

Semantic Versioning

 1# Patch release (bug fixes)
 2git tag v1.0.1
 3git push origin v1.0.1
 4
 5# Minor release (new features, backward compatible)
 6git tag v1.1.0
 7git push origin v1.1.0
 8
 9# Major release (breaking changes)
10# Update go.mod first:
11module github.com/username/mymodule/v2
12
13git tag v2.0.0
14git push origin v2.0.0

Pre-release Versions

 1# Alpha
 2git tag v1.0.0-alpha.1
 3git push origin v1.0.0-alpha.1
 4
 5# Beta
 6git tag v1.0.0-beta.1
 7git push origin v1.0.0-beta.1
 8
 9# Release candidate
10git tag v1.0.0-rc.1
11git push origin v1.0.0-rc.1
12
13# Install pre-release
14go get github.com/username/mymodule@v1.0.0-beta.1

Retract Versions

 1// go.mod
 2module github.com/username/mymodule
 3
 4go 1.21
 5
 6// Retract broken versions
 7retract (
 8    v1.0.1 // Published accidentally
 9    [v1.0.5, v1.0.7] // Security vulnerability
10)

Private Go Modules

Using GOPRIVATE

1# Configure private repos
2go env -w GOPRIVATE=github.com/myorg/*
3
4# Or multiple patterns
5go env -w GOPRIVATE=github.com/myorg/*,gitlab.com/mycompany/*
6
7# With authentication
8git config --global url."https://username:token@github.com/".insteadOf "https://github.com/"

Using Go Proxy

1# Athens (self-hosted Go proxy)
2docker run -p 3000:3000 gomods/athens:latest
3
4# Configure Go to use Athens
5go env -w GOPROXY=http://localhost:3000,direct
6
7# Or with fallback
8go env -w GOPROXY=http://localhost:3000,https://proxy.golang.org,direct

Using Artifactory

1# Configure Artifactory as Go proxy
2go env -w GOPROXY=https://artifactory.example.com/api/go/go-virtual
3
4# With authentication
5# Create ~/.netrc:
6machine artifactory.example.com
7login username
8password token

Module Proxy (pkg.go.dev)

1# After publishing to GitHub, request indexing
2# Visit: https://pkg.go.dev/github.com/username/mymodule@v1.0.0
3
4# Or use proxy directly
5GOPROXY=https://proxy.golang.org go get github.com/username/mymodule@v1.0.0
6
7# Module will appear on pkg.go.dev automatically

Best Practices

 1# 1. Use semantic versioning
 2git tag v1.0.0
 3
 4# 2. Write good documentation
 5# Add examples in _test.go files
 6
 7# 3. Use go.mod replace for local development
 8replace github.com/username/mymodule => ../mymodule
 9
10# 4. Keep dependencies minimal
11go mod tidy
12
13# 5. Test before releasing
14go test ./...
15
16# 6. Use retract for broken versions
17# Add to go.mod:
18retract v1.0.1
19
20# 7. Major version in module path (v2+)
21module github.com/username/mymodule/v2

Example: Publishable Library

 1// mylib.go
 2package mylib
 3
 4import "fmt"
 5
 6// Version of the library
 7const Version = "1.0.0"
 8
 9// Greet returns a greeting message
10func Greet(name string) string {
11    return fmt.Sprintf("Hello, %s!", name)
12}
13
14// Add adds two integers
15func Add(a, b int) int {
16    return a + b
17}
 1// mylib_test.go
 2package mylib_test
 3
 4import (
 5    "testing"
 6    "github.com/username/mymodule/pkg/mylib"
 7)
 8
 9func TestGreet(t *testing.T) {
10    got := mylib.Greet("World")
11    want := "Hello, World!"
12    if got != want {
13        t.Errorf("Greet() = %q, want %q", got, want)
14    }
15}
16
17func ExampleGreet() {
18    fmt.Println(mylib.Greet("World"))
19    // Output: Hello, World!
20}

Publish Checklist

  • Code is tested (go test ./...)
  • Documentation is complete
  • Examples are provided
  • LICENSE file exists
  • README.md is comprehensive
  • go.mod is clean (go mod tidy)
  • Version is tagged (git tag v1.0.0)
  • Pushed to GitHub (git push origin v1.0.0)
  • Verify on pkg.go.dev

Related Snippets