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:
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()
}
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:
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/parser
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:
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:
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 |
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
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?
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
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.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.