220

I am new to go and working on an example code that I want to localize.

In the original main.go import statement it was:

 import (
    "log"
    "net/http"
    "github.com/foo/bar/myapp/common"
    "github.com/foo/bar/myapp/routers"
)

Now I have common and routers package in /home/me/go/src/myapp

So I converted the import statement to:

import (
    "log"
    "net/http"
    "./common"
    "./routers"
)

But when I run go install myapp I get these errors:

can't load package: /home/me/go/src/myapp/main.go:7:3: local import "./common" in non-local package

Also, when I use common and routers instead of ./common and ./routers in the import statement, I get:

myapp/main.go:7:3: cannot find package "common" in any of:
    /usr/local/go/src/common (from $GOROOT)
    /home/me/go/src/common (from $GOPATH)
myapp/main.go:8:2: cannot find package "routers" in any of:
    /usr/local/go/src/routers (from $GOROOT)
    /home/me/go/src/routers (from $GOPATH)

How can I fix this?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Karlom
  • 13,323
  • 27
  • 72
  • 116
  • 11
    All imports are "local" regardless of the import path. See ["How to Write Go Code"](https://golang.org/doc/code.html) for a detailed explanation. – JimB Feb 18 '16 at 15:06
  • 142
    @JimB putting aside the philosophical debates, what I am concerned is how to solve the problem mentioned above. – Karlom Feb 19 '16 at 10:33
  • 6
    I'm not trying to make a philosophical statement, I'm literally saying *all* imports happen in your local filesystem; there is never any difference whether they originate from a remote repo or not. Don't try to use relative paths (they work sometimes, but are discouraged), and go through the "How to Write Go Code" document, specifically the section on ["Code Organization"](https://golang.org/doc/code.html#Organization). – JimB Feb 19 '16 at 15:20
  • Does this answer your question? [Accessing local packages within a go module (go 1.11)](https://stackoverflow.com/questions/52026284/accessing-local-packages-within-a-go-module-go-1-11) – Michael Freidgeim Apr 17 '21 at 05:48
  • The "How to Write Go Code" will invite you to create modules in a shared, global folder ($HOME/hello/morestrings for instance) which seems highly unnatural when coming from other backgrounds. But relative paths are not good either. The "vendor" answer below is an interesting intermediate. In JavaScript, it is similar to using a path alias to a local "packages" folder, that mimicks "real" packages, but let you keep the code within your app. It's useful when you refactor code, but you are not yet sure you actually want the module to be totally independant from the app. – Eric Burel Sep 23 '22 at 13:23
  • And of course the accepted answer also works well, just figuring out the right module name: import "mymodulename/mynestedpackagename" – Eric Burel Sep 23 '22 at 13:34

11 Answers11

140

Well, I figured out the problem. Basically Go starting path for import is $HOME/go/src

So I just needed to add myapp in front of the package names, that is, the import should be:

import (
    "log"
    "net/http"
    "myapp/common"
    "myapp/routers"
)
Karlom
  • 13,323
  • 27
  • 72
  • 116
  • 9
    using project name like `myapp` is a bad idea, for example if you change the project name, all the import will be failed – TomSawyer May 15 '18 at 18:51
  • 15
    What's the alternative? Go doesn't recommend that you use relative imports. – Sam Holmes Aug 02 '18 at 13:08
  • 29
    Of course all the imports will fail if you change the project name. The project name rarely changes. – Damien Roche Aug 02 '18 at 19:09
  • 51
    Well, as of go1.11 you can use the new modules system. `go mod init ` and then just `import "/"`. – shriek Oct 14 '18 at 05:37
  • How we can import github.com/dgrijalva/jwt-go in our .go file? My jwt-go folder is inside src/github.com/dgrijalva – Manik Thakur Jan 22 '20 at 13:18
  • This answer would deserve a bit more details as in https://stackoverflow.com/a/68877864/5513532 Here are my takes: - you need a go.mod only at the root, "myapp/go.mod" for instance with "module myapp" - the nested folders don't need a go.mod. - package vs module can be confusing but basically the convention seems to be "module/nestedFolderName": module is what you find in "go.mod" (myapp) - if it doesn't work, you may have another issue (eg you created your app accidentally in a preexisting module folder, misconfigured text editor...) – Eric Burel Sep 23 '22 at 13:39
  • The first sentence might be outdated, "Basically Go starting path for import is $HOME/go/src" => with go modules, the main app won't necessarily live in "$HOME/go/src", which can be confusing. So the comment above from @shriek as well as the answer https://stackoverflow.com/a/68877864/5513532 are more appropriate in 2022 The main app should be created using "go mod init", and then the import path is just "module/folder". – Eric Burel Sep 23 '22 at 13:43
73

You should have created your package with go mod init e.g. go mod init github.com/my-org/my-package

Now in my-package you have a sub module called utils for example.

main.go
utils
 |- randstr.go

And your randstr.go looks like this:

package utils

func RandStr(n int) string {
    // TODO: Generate random string....
    return "I am a random string"
}

And then anywhere in your project you would use exported (capitalized) functions from the utils package like this, for example in main.go:

package main

import (
    "fmt"

    // "github.com/my-org/my-package" is the module name at the
    // top of your `go.mod`
    "github.com/my-org/my-package/utils"
)

func main() {
    fmt.Printf("Random string: %s\n", utils.RandStr(20))
}
Dominic
  • 62,658
  • 20
  • 139
  • 163
  • 1
    I found your answer to be simple to understand. In general, is it correct to say, that by simply copying the required files in the module directories and following your simple instructions, one can eliminate the use of any Version Control System and still be able to use go modules? I simply do not like the notion of tying version control system to a language's development system and add the related complexities if I can maintain all code, including vendor-ed one locally, by simply copying them. As I get more confident with go, I may integrate use of modules-with-versioning support. – Sunny Aug 23 '21 at 14:50
  • 1
    Worked well for me. This should be the accepted answer – kargirwar Sep 07 '21 at 12:12
  • 3
    Thank you, been almost a day trying to understand import/export in go after moving from nodejs. The easiest answer I found to date. – Suraj Mandal Nov 01 '21 at 03:20
63

If you are using Go 1.5 above, you can try to use vendoring feature. It allows you to put your local package under vendor folder and import it with shorter path. In your case, you can put your common and routers folder inside vendor folder so it would be like

myapp/
--vendor/
----common/
----routers/
------middleware/
--main.go

and import it like this

import (
    "common"
    "routers"
    "routers/middleware"
)

This will work because Go will try to lookup your package starting at your project’s vendor directory (if it has at least one .go file) instead of $GOPATH/src.

FYI: You can do more with vendor, because this feature allows you to put "all your dependency’s code" for a package inside your own project's directory so it will be able to always get the same dependencies versions for all builds. It's like npm or pip in python, but you need to manually copy your dependencies to you project, or if you want to make it easy, try to look govendor by Daniel Theophanes

For more learning about this feature, try to look up here

Understanding and Using Vendor Folder by Daniel Theophanes

Understanding Go Dependency Management by Lucas Fernandes da Costa

I hope you or someone else find it helpfully

arimaulana
  • 1,011
  • 8
  • 6
  • 2
    you mean go lang version 1.15? – Serhii Polishchuk Feb 25 '21 at 20:08
  • @arimaulana works perfectly well for me - GO 1.8 ! – Jia May 18 '22 at 00:49
  • VS Code is not happy, do you know how to tell it to look for packages in the vendor folder? This questions is not answered at the time of writing: https://stackoverflow.com/questions/61602601/how-to-allow-vendor-folder-support-in-visual-studio-code Edit: fixed it by moving my project into its own folder, now it seems to work out of the box. I need a "go.mod" only at top level, not in vendor modules. – Eric Burel Sep 23 '22 at 13:26
  • This should really be the accepted answer. Vendoring seems to be the best approach for importing local packages. – Trevor Sullivan Mar 14 '23 at 06:26
  • Note that your project **must** contain a `go.mod` file that specifies a recent-enough go version for this to work. From [`go-build`'s man page](https://manpages.debian.org/testing/golang-go/go-build.1.en.html#mod): "By default, if a vendor directory is present and the go version in go.mod is 1.14 or higher, the go command acts as if -mod=vendor were set." – Tenders McChiken Aug 20 '23 at 11:24
25

Import paths are relative to your $GOPATH and $GOROOT environment variables. For example, with the following $GOPATH:

GOPATH=/home/me/go

Packages located in /home/me/go/src/lib/common and /home/me/go/src/lib/routers are imported respectively as:

import (
    "lib/common"
    "lib/routers"
)
JimB
  • 104,193
  • 13
  • 262
  • 255
wlredeye
  • 984
  • 1
  • 10
  • 20
  • Yes, the first example was my mistake. – wlredeye Feb 18 '16 at 12:10
  • What you mean by relative path not supported by the tooling? – wlredeye Feb 18 '16 at 12:24
  • 3
    You can't `go install` packages that uses relative imports. – JimB Feb 18 '16 at 13:01
  • I think its misunderstanding here. I mean relative to GOPATH. Not just relative like "../../mypackage" – wlredeye Feb 18 '16 at 13:22
  • That was in reference to the part you fixed about importing relative to the current directory. Yes, all user imports are relative to `$GOPATH/src`. – JimB Feb 18 '16 at 15:05
  • But I already have `export GOPATH=$HOME/go` in my `.bashrc`. How putting the files in `/lib` make a difference? – Karlom Feb 19 '16 at 10:32
  • to import package you need to add relative to `$GOPATH/src` path to your project. `lib/` is just example – wlredeye Feb 19 '16 at 11:04
  • If you are using Go1.11 above, you can follow this [post](https://levelup.gitconnected.com/import-and-use-local-packages-in-your-go-application-885c35e5624) for keeping the relative path – Kino Oct 19 '21 at 03:56
13

an example:

  1. in ./greetings, do go mod init example.com/greetings

  2. from another module, do go mod edit -replace=example.com/greetings=../greetings

  3. go get example.com/greetings

from the go tutorial

siminsimin
  • 301
  • 2
  • 6
10

Follow instructions here https://go.dev/doc/tutorial/call-module-code

Mainly you need the replace call in your go.mod file.

module example.com/hello

go 1.16

replace example.com/greetings => ../greetings
BAR
  • 15,909
  • 27
  • 97
  • 185
8

Local package is a annoying problem in go.

For some projects in our company we decide not use sub packages at all.

  • $ glide install
  • $ go get
  • $ go install

All work.

For some projects we use sub packages, and import local packages with full path:

import "xxxx.gitlab.xx/xxgroup/xxproject/xxsubpackage

But if we fork this project, then the subpackages still refer the original one.

MarAvFe
  • 468
  • 4
  • 15
tangxinfa
  • 1,410
  • 13
  • 12
5

As in the question, the folder structure is:

/home/me/go/src/myapp
                └─ common
                └─ routers

So go to myapp dir

cd /home/me/go/src/myapp

Do

go mod init myapp

This will create a go.mod file which lets Go know the name of the module myapp so that when it’s looking at import paths in any package, it knows not to look elsewhere for myapp

Then you can do the following in the code:

import (
    "log"
    "net/http"
    "myapp/common"
    "myapp/routers"
)

Now package common and routers gets imported.

sunil karki
  • 337
  • 4
  • 3
5

Another approach, available since go1.18, is to use a go.work file.

First, the local common package has to be a module, so provide a go.mod file inside the common folder:

module common

go 1.18

You can now create a go.work file in the root of your directory manually or call go work init, then go work use . and finally go work use ./common. It will look like this:

go 1.18

use (
    .
    ./common
)

Finally you can import the package in your code by name

package main

import "common"

Just remember to not commit your go.work files :)

Inuart
  • 1,432
  • 3
  • 17
  • 28
  • 2
    Why is it a bad idea to commit the `go.work` file if the paths in it are relative to the project anyway? – Igor Jan 31 '23 at 03:45
  • I'm not sure why you would want to do that. Afaik we use a local package while working on it before publishing into it's own repo. Once it's published, there's no need for importing a local package since you can import it normally. If you have a local copy of the package you just use go.work as it is designed. Maybe I'm missing something? – Inuart Apr 11 '23 at 20:56
  • @karlom in 2023, this should probably be the accepted answer. – KobeJohn Jun 20 '23 at 14:09
3

The key is how you name your module in the following command

go mod init <TheNameGiven>

Then refer the modules in the inner folder with,

TheNameGiven/folder

I have found the best solution here... Read More

Chikku Jacob
  • 2,114
  • 1
  • 18
  • 33
2

Try to change the package name with the go mod init command.

So, I have go 1.17, and I have the same import problem. My project directory is $GOPATH/src/myswagger/app-swagger-test. I ran this command into app-swagger-test dir:

go mod init app-swagger-test
go mod tidy

In my new go.mod file the package name is app-swagger-test. For example, this import was wrong:

import (
    ...
    "myswagger/app-swagger-test/internal/generated/restapi"
    "myswagger/app-swagger-test/internal/generated/restapi/operations"
)

So I removed go.mod and go.sum. And I ran next commands into app-swagger-test dir:

go mod init myswagger/app-swagger-test
go mod tidy

After that all imports in the project were imported successfully. In the new go.mod file the first line is:

module myswagger/app-swagger-test

Maybe this information is common, but I did not find it. Thanks!

J.M. Janzen
  • 671
  • 1
  • 8
  • 19