I can not find a way to factor out some code from main.go
into a local package when using Go modules (go version >= 1.11) outside of $GOPATH
.
I am not importing any external dependencies that need to be included into go.mod
, I am just trying to organize locally the source code of this Go module.
The file main.go
:
package main
// this import does not work
import "./stuff"
func main() {
stuff.PrintBaz()
}
The file ./stuff/bar.go
(pretending to be a local package):
package stuff
import "log"
type Bar struct {
Baz int
}
func PrintBaz() {
baz := Bar{42}
log.Printf("Bar struct: %v", baz)
}
The file go.mod
(command go mod init foo
):
module foo
go 1.12
When executing go run main.go
:
- If I
import "./stuff"
, then I seebuild command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff
. - If I
import "stuff"
, then I seebuild command-line-arguments: cannot load stuff: cannot find module providing package stuff
. - If I
import stuff "./stuff"
with a package alias, then I see again:build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff
.
I can not find a way to make local packages work with go modules.
- What's wrong with the code above?
- How can I import local packages into other Go code inside a project defined with Go modules (file
go.mod
)?
Module structure
The most common and easiest approach is:
go.mod
per repository, andgo.mod
file in the repository root, andmodule
line in thego.mod
go.mod
).For example, if your repo is
github.com/my/repo
, then you would place a singlego.mod
in the repo root, with the first line readingmodule github.com/my/repo
. That can be created bycd
'ing to the repo root and runninggo mod init github.com/my/repo
.Following this helps you stay on the happy path with modules, and it avoids multiple subtleties.
Russ Cox commented in #26664:
There is much more about multi-module repositories in the "Multi-module Repositories" FAQ section on the modules wiki. Those 6 or so FAQs in that section should be read in their entirety by anyone considering veering off the recommendation above.
Arranging packages within a module
Once you have set up your
go.mod
, you can arrange your packages in directories however you see fit in directories underneath the directory containing thego.mod
, as well as in the directory with thego.mod
. Three good articles about how to arrange your code in packages:Those articles are classics that pre-date the introduction of modules, but the philosophies in them still apply to how to arrange your packages within a module.
Importing other packages in the same module
When importing another package with modules, you always use the full path including the module path. This is true even when importing another package in the same module. For example, if a module declared its identity in its
go.mod
as modulegithub.com/my/repo
, and you had this organization:Then
pkg1
would import its peer package asimport "github.com/my/repo/pkg2"
. Note that you cannot use relative import paths likeimport "../pkg2"
orimport "./subpkg"
. (This is part of what OP hit above withimport "./stuff"
).Modules vs. repositories vs. packages vs. import paths
A Go module is a collection of related Go packages that are versioned together as a single unit. Modules record precise dependency requirements and create reproducible builds.
Summarizing the relationship between repositories, modules, and packages:
package foo
statement.import "github.com/my/repo/pkg1"
. The import path always starts with the module path of that package, regardless of whether that package is in the same module or a different module.First you have to choose a name for your project and write it to go.mod file. This name belongs to root directory of the project. Each new package you create must be located inside it's own subdirectory and its name should match directory name.
go.mod:
or (preferred way, see @typical182's comment for details)
Then import your project's packages like:
or
Files of package
stuff
should be located inside project'sstuff
directory. You name these files as you like.Also it's possible to create deeper project structure. For instance, you decided to separate source code files from other ones (like app configs, docker files, static files, etc...). Let's move
stuff
directory insidepkg
, every go file insidepkg/stuff
still havestuff
package name. To import stuff package just write:Nothing stops you from creating more levels in the hierarchy like
github.com/myuser/myproject/pkg/db/provider/postgresql
, where:github.com/myuser/myproject
- project name.postgresql
- package name.pkg/db/provider/postgresql
- path to the package relative to project's root.You can read more about go modules here: https://github.com/golang/go/wiki/Modules
Check out this repository to get useful information about various patterns used in project organizing: https://github.com/golang-standards/project-layout If you go inside
pkg
directory you will find out which open source projects usepkg
directory in their structure.