Yes. Modules can contain library packages. In fact, this is the main purpose of a module – to organize packages into versioned libraries.
Short answer: Yes, but…
Long answer: Modules were designed with package avilability in mind. Hence by default, module paths and import paths should point to remote repositories.
However, even if you do not have your library module on any remote repository, you still can pretend that you do.
Use a module path that points to a remote repository. It does not need to exist.
Use the replace directive to tell the Go toolchain that the actual module lies somewhere on your local filesystem.
Your Go code uses import "github.com/yourorg/yourmodule" as import path, just as if the module and its package were available remotely
Then call
go mod edit -replace "github.com/yourorg/yourmodule" => "your/local/path/to/yourmodule"
Now your go.mod file contains a hint to fetch the module and its package locally.
Advantage: Once you are done with local development, you can then push the module to the remote repository, remove the replace directive in go.mod (you can use -dropreplace for that), and you’re done. No need to change all the import paths from local to remote.
go install compiles a binary and installs it into $(GOPATH)/bin. It is of no use for library modules.
See above – use remote module paths and go mod edit -replace.
Thank you for your answer. I am slowly making progress, the replace directive in the go.mod might prove to be helpful (I hope).
I can partially understand why it has been designed as it is, but some of it seems overly restrictive to me. After googling around for the topic of “relative imports” I can find many discussions with strong opinions for and against such desire, and while I can somehow understand why that might be restricted when referring to other modules (as in my case above) I have meanwhile stumbled across something else that I believe is restricted too much for no obvious (to me) reason at all: relative imports INSIDE the same module.
if I wanted to refer to the package sub from within main I am not allowed to just import “./sub” for some reason I have yet to understand this is not allowed.
However, after playing around with replace I came up with the following:
replace _ => ./
and now I seem to be able to import “_/sub”, so I can at least refer to the module root without knowing its name, I can go run or go build the module and it does not complain.
Will this cause me trouble later down the road? If none of these internal sub-packages is ever supposed to be used standalone and merely exists for namespacing and code organization reasons, is there any scenario where this would lead to problems?
This is an interesting hack indeed! As per the docs, replace requires a module path and a replacement path as arguments around the => string. “_” is not exactly a valid module path, hence I would not count on go mod to support this trick forever.
The question I would ask myself in this situation is:
If I do not plan to make a sub-package available to other projects, would I need that sub-package at all?
Especially for small projects, you do not necessarily need to break everything into packages. Instead, you can start by adding everything to package main first and refactor later. And if any piece of code then seems worth going into a separate package with a well-defined package API, then the package might be worth living as a standalone package and being available for other projects through its own fully qualified import path.
Hence the need of fully qualified import paths may seem a restriction at first but may pay off in the long run.