Skip to main content
โšก Calmops

Go Modules: Complete Guide to go mod, Dependencies, and Workspaces

Introduction

Go modules are the standard dependency management system since Go 1.11 (required since Go 1.16). Every Go project is a module with a go.mod file that declares its module path and dependencies. This guide covers everything from basic usage to advanced patterns like workspaces and private modules.

The go.mod File

module github.com/myorg/myapp

go 1.22

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/jackc/pgx/v5 v5.5.0
    golang.org/x/sync v0.6.0
)

require (
    // indirect dependencies (managed automatically)
    github.com/bytedance/sonic v1.10.2 // indirect
    github.com/gin-contrib/sse v0.1.0 // indirect
)
  • module โ€” your module’s import path (usually matches your repository URL)
  • go โ€” minimum Go version required
  • require โ€” direct and indirect dependencies with exact versions

Initializing a Module

# Create a new module
mkdir myapp && cd myapp
go mod init github.com/myorg/myapp

# Creates go.mod:
# module github.com/myorg/myapp
# go 1.22

Adding Dependencies

# Add a specific package (updates go.mod and go.sum)
go get github.com/gin-gonic/gin

# Add a specific version
go get github.com/gin-gonic/[email protected]

# Add latest patch release (compatible with current minor)
go get github.com/gin-gonic/gin@latest

# Add a pre-release version
go get github.com/gin-gonic/[email protected]

# Add from a specific commit
go get github.com/gin-gonic/gin@abc1234

# Add from a branch
go get github.com/gin-gonic/gin@main

After go get, run your code or go mod tidy to update go.sum.

Essential go mod Commands

# Initialize a new module
go mod init github.com/myorg/myapp

# Add missing and remove unused dependencies
go mod tidy

# Download all dependencies to local cache
go mod download

# Copy dependencies to vendor/ directory
go mod vendor

# Verify dependencies haven't been tampered with
go mod verify

# Show why a module is needed
go mod why github.com/stretchr/testify

# Edit go.mod programmatically
go mod edit -require github.com/gin-gonic/[email protected]
go mod edit -droprequire github.com/old/package

# Show module graph
go mod graph

# Print module info
go list -m all                    # all dependencies
go list -m -json all              # JSON format
go list -m -u all                 # show available updates

Upgrading Dependencies

# Upgrade a specific module to latest
go get github.com/gin-gonic/gin@latest

# Upgrade all direct dependencies to latest minor/patch
go get -u ./...

# Upgrade only patch versions (safer)
go get -u=patch ./...

# Check what's outdated
go list -m -u all | grep '\[v'

go mod tidy

go mod tidy is the most important command โ€” run it after any dependency change:

go mod tidy

It:

  1. Adds missing require entries for packages you import
  2. Removes require entries for packages you no longer import
  3. Updates go.sum with checksums for all dependencies

Always commit both go.mod and go.sum.

Version Selection: Minimum Version Selection (MVS)

Go uses Minimum Version Selection โ€” it picks the minimum version that satisfies all requirements. This is predictable and reproducible:

Module A requires: gin v1.8.0
Module B requires: gin v1.9.0
Result: gin v1.9.0 (minimum that satisfies both)

This means upgrading a dependency never happens automatically โ€” you must explicitly request it.

Semantic Versioning and Major Versions

Go modules follow semantic versioning. Major version changes (v2+) require a different import path:

// v1 import
import "github.com/gin-gonic/gin"

// v2 import (different module path)
import "github.com/gin-gonic/gin/v2"
# Install v2
go get github.com/gin-gonic/gin/v2@latest

Replacing Dependencies

Replace a dependency with a local version or fork:

// go.mod
replace (
    // Use a local fork
    github.com/original/pkg => ../my-fork

    // Use a different version
    github.com/original/pkg v1.2.3 => github.com/myfork/pkg v1.2.3-patched

    // Pin to a specific commit
    github.com/original/pkg => github.com/original/pkg v0.0.0-20240101000000-abc123456789
)
# Add a replace directive
go mod edit -replace github.com/original/pkg=../my-fork

Remove replace directives before publishing โ€” they only affect the module that declares them.

Vendor Directory

The vendor/ directory contains a copy of all dependencies for reproducible builds without network access:

# Create vendor directory
go mod vendor

# Build using vendor (ignores module cache)
go build -mod=vendor ./...

# Verify vendor matches go.mod
go mod verify

When to use vendor:

  • CI/CD environments without internet access
  • Auditing all dependency code
  • Ensuring builds are reproducible without a module proxy

Private Modules

For private repositories, configure GONOSUMCHECK and GONOSUMDB:

# Tell Go not to use the public checksum database for private modules
export GONOSUMCHECK=github.com/myorg/*
export GONOSUMDB=github.com/myorg/*
export GOPRIVATE=github.com/myorg/*  # combines both

# For GitHub with SSH authentication
export GOFLAGS=-mod=mod
git config --global url."[email protected]:".insteadOf "https://github.com/"
# .netrc for HTTPS authentication
machine github.com
login your-username
password your-personal-access-token

Go Workspaces (Go 1.18+)

Workspaces let you work on multiple modules simultaneously without replace directives:

# Create a workspace
go work init

# Add modules to the workspace
go work use ./myapp
go work use ./mylib
go work use ../shared-pkg
# go.work
go 1.22

use (
    ./myapp
    ./mylib
    ../shared-pkg
)

Now myapp can import mylib and shared-pkg using their actual module paths, and Go will use the local versions automatically.

# Sync workspace dependencies
go work sync

# Build all modules in workspace
go build ./...

Don’t commit go.work โ€” it’s for local development only. Add it to .gitignore.

Module Proxy

Go downloads modules through a proxy (default: proxy.golang.org):

# Use the default proxy
export GOPROXY=https://proxy.golang.org,direct

# Use a corporate proxy
export GOPROXY=https://goproxy.mycompany.com,https://proxy.golang.org,direct

# Disable proxy (direct downloads only)
export GOPROXY=direct

# China mirror
export GOPROXY=https://goproxy.cn,direct

Common Patterns

Pinning a Dependency Version

# Pin to exact version (prevents accidental upgrades)
go get github.com/critical/[email protected]
// go.mod
require github.com/critical/pkg v1.2.3

Checking for Security Vulnerabilities

# Built-in vulnerability check (Go 1.20+)
go vuln check

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

Dependency Graph Visualization

# Install modgraphviz
go install golang.org/x/exp/cmd/modgraphviz@latest

# Generate dependency graph
go mod graph | modgraphviz | dot -Tpng -o deps.png

Quick Reference

Command Purpose
go mod init <path> Initialize new module
go mod tidy Add missing, remove unused deps
go get <pkg>@<version> Add/update dependency
go get -u ./... Upgrade all deps
go mod download Download to cache
go mod vendor Copy deps to vendor/
go mod verify Verify checksums
go mod why <pkg> Why is this dep needed?
go list -m -u all Show available updates

Resources

Comments