Section 02
Dependency Management
Every Java project starts with a pom.xml or build.gradle. Go has a single, built-in module system: go mod. No plugins, no wrapper scripts — just the go tool.
Initialising a module
Java — Maven / Gradle
# Maven archetype
mvn archetype:generate \
-DgroupId=com.mycompany \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart
# Gradle init
gradle init --type java-applicationGo — go mod init
# One command, one file created
go mod init github.com/mycompany/my-app
# Creates go.mod:
# module github.com/mycompany/my-app
# go 1.24ℹThe module path (
github.com/mycompany/my-app) is the canonical import path used by other modules to import your code. It does not have to be a real URL for private projects, but using a domain you own avoids future collisions.go.mod and go.sum
Java — pom.xml
<!-- pom.xml -->
<project>
<groupId>com.mycompany</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>com.github.gin-gonic</groupId>
<artifactId>gin</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
</project>Go — go.mod
module github.com/mycompany/my-app
go 1.24
require (
github.com/gin-gonic/gin v1.9.1
)pom.xml / build.gradlego.mod
~/.m2/repository (local cache)$(go env GOPATH)/pkg/mod
maven-wrapper / gradlewgo binary (ships with Go install)
mvn install / gradle buildgo build ./...
mvn dependency:resolvego mod tidy
lockfile (Gradle: .lockfile)go.sum (cryptographic checksums)
Why Go does this
go.sum stores a cryptographic hash for every dependency version downloaded — both the module zip and its go.mod. If a dependency is tampered with on the proxy, the checksum mismatch fails the build. It is stricter than Maven's approach, and should be committed to source control.Adding and removing dependencies
day-to-day dependency commands
# Add a dependency (downloads, updates go.mod + go.sum)
go get github.com/gin-gonic/gin@v1.9.1
# Add latest version
go get github.com/gin-gonic/gin@latest
# Remove unused dependencies + add missing ones
go mod tidy
# Download all dependencies to local cache (useful in CI)
go mod download
# View dependency graph
go mod graph
# Explain why a dependency is present
go mod why github.com/some/package→Run
go mod tidy before committing. It removes unused entries from go.mod/go.sum and ensures every import in your code has a matching require directive. The equivalent of cleaning up unused Maven dependencies, automatically.Semantic import versioning
Go enforces a convention that has no Maven/Gradle equivalent: when a module releases a v2 or higher breaking change, the module path itself changes to include /v2. This means old and new major versions can coexist in the same binary.
v1 and v2 of the same library can coexist
// go.mod
require (
github.com/some/lib v1.5.0 // v1 — path has no suffix
github.com/some/lib/v2 v2.1.0 // v2 — path has /v2 suffix
)
// In Go source, each is a separate import path:
import libv1 "github.com/some/lib"
import libv2 "github.com/some/lib/v2"
// No dependency hell — both versions compile into the same binary
// without shadowing each other.replace directive — local development
Java — mvn install to local .m2
# Build and install to local Maven repo
cd ../my-shared-lib
mvn install
# pom.xml in the depending project
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my-shared-lib</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>Go — replace directive
// go.mod in your project
require github.com/mycompany/shared-lib v0.0.0
// redirect to a local path — no publishing needed
replace github.com/mycompany/shared-lib => ../shared-lib
// Remove the replace directive before publishing.
// go mod tidy will warn if a replace points nowhere.!
replace is for local development only. Never publish a module to a registry with a replace directive pointing to a relative path — consumers cannot resolve it.Pinning tool dependencies (Go 1.24+)
Code generators and linters used in go generate or CI need to be pinned to a specific version. Before Go 1.24, the idiom was a tools.go file with blank imports — a confusing workaround. Go 1.24 added a tool directive to go.mod.
Java — build plugin versions
<!-- pom.xml — plugin version is pinned here -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>Go 1.24+ — tool directive
// go.mod — pin code-gen tools here
module github.com/mycompany/my-app
go 1.24
require (
github.com/gin-gonic/gin v1.9.1
)
tool (
github.com/sqlc-dev/sqlc/cmd/sqlc
github.com/mailru/easyjson/easyjson
)
// Run pinned tools via: go tool sqlc generate
// go mod tidy keeps tool versions in sync with go.sumℹBefore Go 1.24, the community used a
tools.go file with //go:build tools and blank imports (_ "github.com/sqlc-dev/sqlc/cmd/sqlc") to force go.sum to track tool versions. You will see this pattern in older codebases.Private modules
configure GONOSUMCHECK / GOFLAGS for private repos
# Tell Go not to fetch private modules via the public proxy
# (proxy.golang.org does not have access to your private repos)
export GONOSUMCHECK="github.com/mycompany/*"
export GOFLAGS="-mod=mod"
export GOPRIVATE="github.com/mycompany/*"
# GOPRIVATE sets both GONOSUMCHECK and GONOPROXY at once.
# Git credentials (SSH or token) handle auth — same as Maven's settings.xml