Go 1.11 is out, and it includes modules (formerly vgo). Finally, official dependency management!

The Problem

Before modules, Go had:

  • GOPATH (confusing for beginners)
  • dep (community tool, not official)
  • Vendor directories (manual management)
  • No version pinning

It was a mess.

What Are Modules?

Modules are Go’s official dependency management system. They:

  • Work outside GOPATH
  • Pin dependency versions
  • Use semantic versioning
  • Generate lock files

Getting Started

# Initialize a module
go mod init github.com/myuser/myproject

# This creates go.mod

go.mod file:

module github.com/myuser/myproject

go 1.11

require (
    github.com/gin-gonic/gin v1.4.0
    github.com/lib/pq v1.2.0
)

Adding Dependencies

Just import and use:

package main

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

func main() {
    r := gin.Default()
    r.Run()
}

Then:

go build  # Automatically downloads dependencies

Or explicitly:

go get github.com/gin-gonic/gin@v1.4.0

Semantic Versioning

Modules use semver:

# Latest version
go get github.com/gin-gonic/gin

# Specific version
go get github.com/gin-gonic/gin@v1.4.0

# Specific commit
go get github.com/gin-gonic/gin@abc123

# Latest patch release
go get github.com/gin-gonic/gin@v1.4

The go.sum File

go.sum is the lock file:

github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:58S9LJ4k/4vN6vVqXOnV3/3iwYDN9OZCaCsK0We9Rl8=

Commit this to version control.

Upgrading Dependencies

# Upgrade all dependencies
go get -u

# Upgrade specific dependency
go get -u github.com/gin-gonic/gin

# Upgrade to specific version
go get github.com/gin-gonic/gin@v1.5.0

Vendoring

Still want vendor directory?

go mod vendor

This copies dependencies to vendor/.

Migrating from dep

We had a project using dep:

# Remove dep files
rm Gopkg.lock Gopkg.toml

# Initialize modules
go mod init

# Tidy up
go mod tidy

Go modules automatically imported our dep dependencies!

Private Repositories

For private repos:

# Configure Git to use SSH
git config --global url."git@github.com:".insteadOf "https://github.com/"

# Set GOPRIVATE
export GOPRIVATE=github.com/mycompany/*

Multi-Module Repositories

You can have multiple modules in one repo:

myrepo/
├── go.mod          # Root module
├── api/
│   └── go.mod      # API module
└── worker/
    └── go.mod      # Worker module

Replace Directive

For local development:

// go.mod
module github.com/myuser/myproject

require github.com/myuser/mylib v1.0.0

replace github.com/myuser/mylib => ../mylib

Now changes to ../mylib are immediately reflected.

Our Experience

We migrated 10 projects from dep to modules. It was smooth:

  1. Run go mod init
  2. Run go mod tidy
  3. Test
  4. Commit go.mod and go.sum

Total time: ~1 hour for all projects.

Benefits

1. No More GOPATH

Projects can live anywhere:

cd ~/projects/myapp  # Not in GOPATH
go build             # Works!

2. Reproducible Builds

go.sum ensures everyone gets the same dependencies.

3. Faster Downloads

Module cache is shared across projects:

# Cache location
~/go/pkg/mod/

4. Semantic Versioning

Clear versioning makes upgrades safer.

Issues We Hit

1. v2+ Modules

Modules v2+ must include version in import path:

// v1
import "github.com/myuser/mylib"

// v2
import "github.com/myuser/mylib/v2"

This is confusing but necessary for compatibility.

2. Pseudo-Versions

Untagged commits get pseudo-versions:

v0.0.0-20180901003855-c67002cb31c3

Ugly but functional.

3. Minimal Version Selection

Go modules use “minimal version selection”, not “latest version selection”.

This can be surprising but is more predictable.

Should You Use Modules?

Yes, if:

  • Starting a new project
  • Want to work outside GOPATH
  • Need reproducible builds

Wait, if:

  • On Go < 1.11
  • dep is working fine for you

We’re using modules for all new projects. Migrating old projects gradually.

The Future

Modules are the future of Go dependency management. dep is deprecated.

Go 1.13 will make modules the default.

Commands Cheat Sheet

# Initialize
go mod init github.com/user/repo

# Add dependency
go get github.com/pkg/errors

# Upgrade all
go get -u

# Tidy up
go mod tidy

# Vendor
go mod vendor

# Verify
go mod verify

# Graph
go mod graph

The Verdict

Go modules are a huge improvement. They’re simple, official, and work well.

If you’re not using them yet, give them a try.

Questions? Let me know!