Question
I am new to Go and trying to run an example project locally.
The original main.go file used these imports:
import (
"log"
"net/http"
"github.com/foo/bar/myapp/common"
"github.com/foo/bar/myapp/routers"
)
I now have the common and routers packages stored locally in:
/home/me/go/src/myapp
So I changed the imports to use relative paths:
import (
"log"
"net/http"
"./common"
"./routers"
)
But when I run:
go install myapp
I get this error:
can't load package: /home/me/go/src/myapp/main.go:7:3: local import "./common" in non-local package
If I change the imports to just common and routers instead of ./common and ./routers, 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 should local packages be imported correctly in Go, and how can I fix this project structure so the imports work?
Short Answer
By the end of this page, you will understand how Go resolves package imports, why relative imports like ./common usually fail, and how to structure a project correctly using either GOPATH-style imports or Go modules. You will also learn the most common fixes for local package import errors.
Concept
In Go, imports are based on package paths, not on arbitrary relative file paths in normal application code.
When you write an import such as:
import "github.com/foo/bar/myapp/common"
Go expects that package to exist at a matching location in your workspace or module.
Why ./common fails
A relative import like this:
import "./common"
is called a local import. Go does not allow local imports in ordinary non-local packages because they make code harder to organize, share, and build consistently.
That is why you see:
local import "./common" in non-local package
Why common also fails
If you import just:
import "common"
Go treats that as a top-level package path. In GOPATH mode, it looks for:
$GOROOT/src/common$GOPATH/src/common
But your package is actually inside:
/home/me/go/src/myapp/common
So the correct import path would need to include myapp as part of the path.
The key idea
In Go, the import path should match the package's location relative to the project root used by Go.
There are two main ways this works:
- GOPATH mode: imports are based on directories under
$GOPATH/src - Module mode: imports are based on the module name from
go.mod
Modern Go prefers modules.
Mental Model
Think of Go imports like postal addresses.
./commonis like saying, "the house next door".commonis like saying only the street name.myapp/commonorexample.com/myapp/commonis the full address.
Go prefers full, stable addresses so it always knows exactly where a package belongs, no matter where the code is built.
If your project is a small neighborhood, then:
- the project root is the neighborhood name
- each folder is a house
- the import path is the full address
That is why common alone is too vague, and ./common is not the normal way Go wants application packages referenced.
Syntax and Examples
In modern Go, you usually define a module first and then import packages using the module path.
Example project structure
myapp/
├── go.mod
├── main.go
├── common/
│ └── common.go
└── routers/
└── routers.go
Option 1: Using Go modules
go.mod
module myapp
go 1.22
main.go
package main
import (
"log"
"net/http"
"myapp/common"
"myapp/routers"
)
func main() {
common.Setup()
router := routers.New()
log.Println(http.ListenAndServe(":8080", router))
}
common/common.go
package common
import "fmt"
func Setup() {
fmt.Println("common setup")
}
routers/routers.go
package routers
import "net/http"
func New() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
})
return mux
}
In this setup, myapp/common means:
- module name:
myapp - package folder:
common
Option 2: Older GOPATH-style layout
If you are working in GOPATH mode and your app is in:
/home/me/go/src/myapp
then imports should be:
import (
"myapp/common"
"myapp/routers"
)
because Go resolves them relative to $GOPATH/src.
Important rule
The package name inside the file and the import path are related but not identical:
- folder path determines the import path
package commondetermines the package name used in code
Example:
import "myapp/common"
func main() {
common.Setup()
}
Step by Step Execution
Consider this project:
/home/me/go/src/myapp
├── main.go
├── common/
│ └── common.go
└── routers/
└── routers.go
And this main.go:
package main
import (
"myapp/common"
)
func main() {
common.Setup()
}
What Go does step by step
1. Reads the import path
Go sees:
import "myapp/common"
2. Resolves the base location
In GOPATH mode, Go checks:
$GOPATH/src/myapp/common
If $GOPATH is /home/me/go, then the full folder becomes:
/home/me/go/src/myapp/common
3. Loads the package files
Go reads .go files in that folder.
For example:
package common
func Setup() {}
4. Verifies package name
The files in that folder must declare:
package common
5. Compiles the package
If the code is valid, Go compiles common.
6. Compiles main
Now main.go can use:
common.Setup()
because the imported package name is common.
Why common alone fails
If you import:
import "common"
Go looks for:
$GOPATH/src/common
but your folder is actually:
$GOPATH/src/myapp/common
So Go cannot find it.
Real World Use Cases
Package imports are used everywhere in real Go programs.
Splitting an app into features
A web app might have packages like:
myapp/routersmyapp/databasemyapp/authmyapp/config
This keeps code organized by responsibility.
Reusing shared helpers
A common or utils package may contain:
- logging setup
- environment loading
- helper functions
- shared constants
Separating HTTP logic from business logic
You might keep:
- routing in
routers - request handlers in
handlers - business logic in
services - database logic in
repository
Imports allow each layer to use the others cleanly.
Building CLI tools
A command-line project may use packages such as:
mytool/parsermytool/outputmytool/config
Each package is imported by the main command package.
Sharing internal libraries within one repo
In larger projects, teams create reusable packages for:
- authentication
- configuration
- validation
- API clients
Real Codebase Usage
In real codebases, developers rarely use relative imports for app code. Instead, they organize packages under a module and import them with stable paths.
Common patterns
Feature-based packages
Projects often group code by feature:
myapp/
├── handlers/
├── routers/
├── models/
├── config/
└── storage/
Small shared packages
A package like config or common is used for startup logic:
import "myapp/config"
Guard clauses during setup
Startup code often imports configuration or setup packages and exits early on error:
cfg, err := config.Load()
if err != nil {
log.Fatal(err)
}
Error handling across packages
Different packages expose functions that return errors:
db, err := storage.Connect()
if err != nil {
return err
}
Internal packages
In bigger repositories, developers may use an internal directory to limit access:
myapp/
├── internal/
│ └── config/
└── main.go
Then code inside the module can import:
import "myapp/internal/config"
This is a common way to keep implementation details private within a repo.
Practical advice
For new Go projects today:
- create a
go.mod - choose a module path
- import packages using that path
- avoid relative imports like
./common
Common Mistakes
Here are the most common mistakes beginners make with Go imports.
1. Using relative imports in application code
Broken
import "./common"
Why it fails
Go rejects local imports in normal package builds.
Fix
Use the full package path:
import "myapp/common"
2. Importing only the folder name
Broken
import "common"
Why it fails
Go searches for common at the top of the workspace, not inside myapp.
Fix
Include the project path:
import "myapp/common"
3. Folder path does not match import path
If your import says:
import "myapp/routers"
then the package must exist in the matching folder.
Fix
Make sure your structure matches the import path exactly.
4. Wrong package declaration inside files
Broken
File: common/common.go
package utils
while you use:
common.Setup()
Why it fails
The code name comes from the declared package, not the folder name alone.
Fix
Use:
package common
or import with an alias if needed.
5. Mixing GOPATH mode and module mode
Beginners sometimes follow old tutorials that assume GOPATH, while their system uses modules.
Fix
Prefer modules unless you specifically need old GOPATH behavior.
6. Running commands from the wrong location
If you are using modules, run commands from the module root where go.mod exists.
Fix
cd /path/to/myapp
go run .
Comparisons
| Approach | Example import | When it works | Recommended? | Notes |
|---|---|---|---|---|
| Relative import | "./common" | Very limited cases | No | Not for normal application package structure |
| Bare package name | "common" | Only if package is at top-level import root | Usually no | Go looks in $GOROOT/src or $GOPATH/src |
| GOPATH-style full path | "myapp/common" | In GOPATH mode when package is in $GOPATH/src/myapp/common | Acceptable for old setups | Matches workspace layout |
| Module-based import | "myapp/common" or "github.com/me/myapp/common" | In module mode with matching go.mod | Yes | Modern Go standard |
GOPATH vs Modules
| Topic | GOPATH mode | Module mode |
|---|---|---|
| Project location | Must be under $GOPATH/src | Can be almost anywhere |
| Import base | Filesystem under GOPATH | Module path in go.mod |
| Modern usage | Older style | Preferred |
| Dependency management | Less flexible | Built-in and standard |
package name vs import path
| Item | Example | Meaning |
|---|---|---|
| Import path | myapp/common | Where Go finds the package |
| Package name | package common | Name used in code after import |
| Usage in code | common.Setup() | Calling exported items from that package |
Cheat Sheet
Quick rules
- Do not use
./commonfor normal Go application imports. - Import paths should match your project structure.
- In GOPATH mode, imports are relative to
$GOPATH/src. - In module mode, imports are relative to the module name in
go.mod.
If your project is:
myapp/
├── go.mod
├── main.go
└── common/
Use:
import "myapp/common"
If your project is under GOPATH:
$GOPATH/src/myapp/common
Use:
import "myapp/common"
Common commands
Create a module
go mod init myapp
Run the app
go run .
Build the app
go build
Common errors
Error
local import "./common" in non-local package
Meaning
You used a relative import where Go expects a package path.
Error
cannot find package "common"
Meaning
Your import path is incomplete. Go cannot find the package at the top level.
Safe default for modern Go
- Create
go.mod - Set a module name
- Import local packages as
module-name/package-name - Avoid GOPATH-specific assumptions unless needed
FAQ
Why can't I use ./common in Go?
Because Go expects package imports to use stable package paths in normal projects. Relative imports are not the standard approach for application code.
Should I use GOPATH or Go modules?
Use Go modules for new projects. GOPATH is older and mostly kept for backward compatibility.
If my folder is myapp/common, what should I import?
Import it as:
import "myapp/common"
if myapp is your module name or GOPATH project root.
Does the folder name have to match the package name?
It usually should, and that is the normal convention. The actual code name comes from the package declaration inside the files.
Can I keep my project outside $GOPATH/src?
Yes, if you use Go modules. That is one of the main benefits of modules.
What should my go.mod contain for a local project?
A simple start is:
module myapp
go 1.22
Why does import "common" not work?
Because Go looks for a top-level package named common, not myapp/common.
What command should I use after creating go.mod?
Usually:
go run .
or:
go build
Mini Project
Description
Build a small Go app with two local packages: one for configuration-style setup and one for HTTP routing. This demonstrates the correct way to organize and import local packages using a module path instead of relative imports.
Goal
Create a working Go project where main.go imports two local packages and starts a small HTTP server successfully.
Requirements
- Create a Go module for the project.
- Add a
commonpackage with one exported setup function. - Add a
routerspackage that returns anhttp.Handler. - Import both packages in
main.gousing the module path. - Run the app and verify it serves a response on
/.
Keep learning
Related questions
Are Go Maps Passed by Value or Reference?
Learn Go map parameter and return semantics: maps are passed by value, while copies share underlying data. Know when map pointers are useful.
Authentication for Go REST APIs: Sessions, Tokens, and Middleware
Learn practical authentication patterns for Go REST APIs, including password hashing, server sessions, bearer tokens, middleware, and security rules.
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.