How To Use Go 1.14 Modules With Local Packages

Eric Semeniuc

Eric Semeniuc

March 16, 2020

Let’s do a simple example: you want to create a package foo which has your business logic, and want to have a small main driver (ie. make it executable, and not a library only).

Starting out

Here’s our starting folder structure:

.
├── README.md
└── main.go

Contents of main.go:

package main

import "fmt"

func main() {
	fmt.Println("hi")
}

Adding a package

We want to make a package foo that has logic, so we make a directory for foo, and foo/foo.go file with a doWork() function.

New folder structure:

.
├── README.md
├── foo
│   └── foo.go
└── main.go

Here’s the contents of foo/foo.go

package foo

func DoWork() int {
	return 42
}

Lets initialize the module:

➜  cd foo && go mod init foo
go: creating new go.mod: module foo

Here’s the layout now:

.
├── README.md
├── foo
│   ├── foo.go
│   └── go.mod
└── main.go

Notice that foo/go.mod has been created with the contents:

module foo

go 1.14

We can run go mod tidy from the foo directory to automatically find all dependencies used in foo and download them.

Using our new package

Now lets make use of foo in our main.go file.

package main

import (
	"fmt"
	"foo"
)

func main() {
	fmt.Println(foo.DoWork())
}

We also need to tell Go that we want to use a local package, so we need to make a new mod.go file from the project root.

➜  cd .. && go mod init main
go: creating new go.mod: module main

Here’s our folder structure now:

.
├── README.md
├── foo
│   ├── foo.go
│   └── go.mod
├── go.mod
└── main.go

We need to tell the compiler that we want to use our local library, so we append replace foo => ./foo to go.mod. Check the Go Wiki for more info about modules.

This is go.mod after the modification:

module main  
  
go 1.14  
  
replace foo => ./foo

Let’s run it

➜  go run main
go: found foo in foo v0.0.0-00010101000000-000000000000
42

It works! Also notice that our main go.mod file was automatically updated to add foo to the list of modules:

module main  
  
go 1.14  
  
replace foo => ./foo  
  
require foo v0.0.0-00010101000000-000000000000

The require foo v0.0.0-00010101000000-000000000000 line tells the Go compiler which version of a dependency we are using. In this case, it’s unversioned since it’s local. If we used a library from GitHub, eg. graphql-go, we would have a line like github.com/graph-gophers/graphql-go v0.0.0-20200309224638-dae41bde9ef9.

Finished Project

See https://github.com/esemeniuc/goModuleDemo for the complete project