How does go mod work

`go mod` manages Go modules by tracking dependencies in a `go.mod` file and storing resolved versions in a `go.sum` file to ensure reproducible builds.

go mod manages Go modules by tracking dependencies in a go.mod file and storing resolved versions in a go.sum file to ensure reproducible builds. It replaces the old GOPATH workflow by allowing projects to define their own dependency tree, fetch packages from version control systems, and lock specific versions to prevent unexpected updates.

When you run go mod init, it creates a go.mod file defining your module path. As you import packages, go automatically fetches them and updates go.mod with the minimum required versions. The go.sum file acts as a checksum database, ensuring that the exact same binary artifacts are downloaded every time, which is critical for security and consistency.

Here is a practical workflow to initialize and manage dependencies:

# Initialize a new module named "example.com/myapp"
go mod init example.com/myapp

# Add a specific version of a dependency (e.g., Gin framework)
go get github.com/gin-gonic/gin@v1.9.0

# Tidy up the go.mod file by removing unused dependencies and adding missing ones
go mod tidy

In your Go code, you simply import the package normally. The tool handles the rest:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/hello", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "Hello"})
    })
    r.Run(":8080")
}

If you need to update all dependencies to their latest compatible versions (respecting the version constraints in go.mod), use go get -u. To force a specific version of a transitive dependency that isn't directly imported, you can use go get with the @ syntax, which adds a "replace" or direct requirement entry.

The go.sum file is critical here; it contains hashes for every downloaded module. If a dependency's content changes on the remote server without a version bump, go will detect the hash mismatch and refuse to build, protecting you from supply chain attacks or silent breakages. You should never manually edit go.sum; always let go mod tidy or go get manage it.

For local development where you might be working on a fork of a dependency, you can use the replace directive in go.mod to point a module path to a local directory:

replace github.com/gin-gonic/gin => ../local-gin-fork

This allows you to test changes in the dependency without publishing a new version. Once your changes are ready, you remove the replace directive and run go mod tidy to lock in the official version.