Question
Even though GOPATH is set correctly, why can go build and go run not find my own package? What is wrong with this project layout?
$ echo $GOROOT
/usr/local/go
$ echo $GOPATH
/home/mitchell/go
$ cat ~/main.go
package main
import "foobar"
func main() {}
$ cat /home/mitchell/go/src/foobar.go
package foobar
$ go build main.go
main.go:3:8: import "foobar": cannot find package
Short Answer
Go does not search every .go file directly inside GOPATH/src. In GOPATH mode, an import path such as "foobar" maps to a directory: $GOPATH/src/foobar. You will learn the required layout, why the error occurs, and how to use Go modules for new projects.
Concept
An import in Go names a package path, not a particular Go file.
In the example:
import "foobar"
When using legacy GOPATH mode, Go looks for the package source in this directory:
/home/mitchell/go/src/foobar
It then compiles the Go files in that directory that declare:
package foobar
However, the source file is currently here:
/home/mitchell/go/src/foobar.go
That is a file alongside the workspace's src contents, not a package directory named foobar. Therefore, Go cannot resolve the import path.
The GOPATH workspace convention is:
$GOPATH/
├── src/ source packages
├── pkg/ compiled package cache (legacy)
└── bin/ installed executable commands
For new Go code, use Go modules instead of organizing projects around GOPATH. Modules explicitly define a project's import path and dependencies in a go.mod file. GOPATH is still used by Go for caches and installed tools, but it is no longer the normal place to put project source code.
Mental Model
Think of an import path as a mailing address for a folder.
If you write:
import "foobar"
Go addresses the package to the foobar folder inside its source root. It expects to find a building at this address:
$GOPATH/src/foobar/
Placing a file named foobar.go directly in $GOPATH/src is like writing a person's name on an envelope but leaving out their street address. The names look related, but Go needs the matching directory structure to locate the package.
Syntax and Examples
In legacy GOPATH mode, a package import path maps to a directory below $GOPATH/src.
$GOPATH/src/<import-path>/*.go
For import "foobar", use this structure:
/home/mitchell/go/
└── src/
├── foobar/
│ └── foobar.go
└── myapp/
└── main.go
/home/mitchell/go/src/foobar/foobar.go:
package foobar
func Message() string {
return "Hello from foobar"
}
/home/mitchell/go/src/myapp/main.go:
package main
import (
"fmt"
"foobar"
)
func main() {
fmt.Println(foobar.Message())
}
Run the application from its directory:
cd /home/mitchell/go/src/myapp
go run .
The package directory is named foobar because that is the import path. The Go file inside it can have another filename, such as message.go; filenames do not determine the import path.
Step by Step Execution
Consider this legacy GOPATH-mode import:
import "foobar"
Go resolves it as follows:
-
It reads
GOPATH:/home/mitchell/go -
It adds
src/because source packages are stored below$GOPATH/src./home/mitchell/go/src -
It appends the import path,
foobar./home/mitchell/go/src/foobar -
It searches that directory for buildable
.gofiles whose package declaration ispackage foobar. -
In the original layout, only this file exists:
/home/mitchell/go/src/foobar.goThis is not inside
/home/mitchell/go/src/foobar, so the package lookup fails. -
Moving the file to this location makes the import resolvable:
/home/mitchell/go/src/foobar/foobar.go
For a modern module project, Go instead begins import resolution with the current module's go.mod file and its declared module path.
Real World Use Cases
Package paths and directory layout matter whenever one Go package uses another:
- Application layers: A
mainpackage imports internal code such asexample.com/shop/internal/orders. - Reusable libraries: A package such as
example.com/company/loggingexposes shared logging helpers. - API services: A server command imports packages for routing, database access, and request validation.
- Command-line tools: A
cmd/toolcommand imports business logic from a separate package. - Multi-package repositories: A project may keep related packages in directories such as
config,storage, andservice.
In all cases, Go identifies a package by its import path and directory, rather than by a single filename.
Real Codebase Usage
Modern Go projects usually use modules and keep commands separate from reusable packages.
Example layout:
weather-cli/
├── go.mod
├── cmd/
│ └── weather/
│ └── main.go
└── internal/
└── forecast/
└── forecast.go
go.mod might declare:
module example.com/acme/weather-cli
Then main.go can import the local package with its module-based path:
import "example.com/acme/weather-cli/internal/forecast"
Common project patterns include:
- Commands in
cmd/: Each subdirectory is usually one executable program. - Internal packages: Put implementation details in
internal/to prevent unrelated modules from importing them. - Small focused packages: Group files by responsibility, not by file extension or class-like types.
- Explicit dependencies: Record third-party dependencies in
go.modandgo.sum. - Package-level tests: Keep
*_test.gofiles alongside the package they test.
Avoid manually copying dependency source into GOPATH for new projects. Use go mod init, go get, and go mod tidy instead.
Common Mistakes
Putting a package file directly in GOPATH/src
This does not create the foobar import path:
$GOPATH/src/foobar.go
Use a directory:
$GOPATH/src/foobar/foobar.go
Assuming the filename controls the import path
This is valid:
$GOPATH/src/foobar/message.go
as long as message.go contains:
package foobar
The folder determines the import path; the filename does not.
Mixing packages in one directory
Non-test Go files in the same directory generally must use one package name.
Broken example:
// first.go
package foobar
// second.go
package main
Avoid putting executable package main code and reusable package foobar code in the same folder.
Using GOPATH layout for a new module project
Modern Go defaults to module-aware behavior. Create a module instead:
go mod init example.com/yourname/myapp
Then use imports beginning with that module path.
Confusing GOROOT with GOPATH
GOROOTidentifies the Go installation and standard library location.GOPATHwas the legacy workspace root and is now mainly used for caches and installed binaries.
Changing GOROOT does not fix an incorrectly placed application package.
Importing a package but never using it
After Go finds a package, this can still fail:
import "foobar"
func main() {}
Go rejects unused imports. Use an exported identifier, such as foobar.Message(), or remove the import.
Comparisons
| Topic | GOPATH mode | Go modules |
|---|---|---|
| Project location | Normally under $GOPATH/src | Can be in almost any directory |
| Local import path | Derived from directory below src | Derived from the module line in go.mod |
| Dependency tracking | Historically stored in workspace directories | Recorded in go.mod and checksums in go.sum |
| Recommended for new projects | No | Yes |
| Item | Determines it | Example |
|---|---|---|
| Import path | Module path plus package directory, or GOPATH src directory in legacy mode | example.com/acme/app/config |
| Package name | The package declaration | package config |
| Go filename | Chosen by the developer | config.go |
A package name often matches its final directory name, but it is the import path and directory layout that let Go find the package.
Cheat Sheet
Legacy GOPATH lookup:
import "name" -> $GOPATH/src/name/
import "a/b" -> $GOPATH/src/a/b/
Correct GOPATH package layout:
$GOPATH/src/foobar/foobar.go
// foobar.go
package foobar
func Message() string { return "hello" }
// main.go
package main
import (
"fmt"
"foobar"
)
func main() {
fmt.Println(foobar.Message())
}
# Modern project setup
go mod init example.com/yourname/project
go run .
go mod tidy
Rules to remember:
- Imports identify packages, not individual
.gofiles. - A package is a directory containing Go source files.
- Files in one directory generally share one
packagedeclaration. GOROOTis the Go installation; it is not your project workspace.- Prefer Go modules for new code.
FAQ
Why does Go look for a directory rather than foobar.go?
A package can contain multiple Go files. Go compiles the package directory as a unit, so imports refer to directories rather than filenames.
What exact folder should import "foobar" use in GOPATH mode?
Place Go source files for that package in $GOPATH/src/foobar/, for example $GOPATH/src/foobar/foobar.go.
Does the Go filename have to match the package name?
No. message.go, client.go, and helpers.go may all declare package foobar in the same foobar directory.
Should I still put projects inside GOPATH?
Usually no. New projects should use Go modules, which let you work outside GOPATH and manage dependencies with go.mod.
How do I start a Go module?
From the project root, run:
go mod init example.com/yourname/project
Use a module path appropriate for where the code will live, especially if it will be published.
Why does Go report an unused import after it finds my package?
Go requires every import to be used in the file. Call an exported function, reference an exported type, or remove the import.
Can package main import another package main?
No. Put reusable code in a non-main package. A main package is intended to build an executable command.
Mini Project
Description
Build a small Go module with a command package and a reusable greeting package. This demonstrates the modern equivalent of organizing code into importable package directories, without requiring the project to be inside GOPATH.
Goal
Create and run a command that imports a local package using the module path declared in go.mod.
Requirements
Create a project directory containing a go.mod file.
Declare the module path as example.com/greeter.
Create a greeting package in its own directory with a function that returns a greeting.
Create a main package that imports example.com/greeter/greeting.
Run the application with go run . from the project root.
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.