Question

How to Import Local Packages in Go

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:

  1. GOPATH mode: imports are based on directories under $GOPATH/src
  2. 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.

  • ./common is like saying, "the house next door".
  • common is like saying only the street name.
  • myapp/common or example.com/myapp/common is 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.

Take Quiz

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 common determines 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/routers
  • myapp/database
  • myapp/auth
  • myapp/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
  • mytool/output
  • mytool/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
Take Quiz

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

ApproachExample importWhen it worksRecommended?Notes
Relative import"./common"Very limited casesNoNot for normal application package structure
Bare package name"common"Only if package is at top-level import rootUsually noGo looks in $GOROOT/src or $GOPATH/src
GOPATH-style full path"myapp/common"In GOPATH mode when package is in $GOPATH/src/myapp/commonAcceptable for old setupsMatches workspace layout
Module-based import"myapp/common" or "github.com/me/myapp/common"In module mode with matching go.modYesModern Go standard

GOPATH vs Modules

TopicGOPATH modeModule mode
Project locationMust be under $GOPATH/srcCan be almost anywhere
Import baseFilesystem under GOPATHModule path in go.mod
Modern usageOlder stylePreferred
Dependency managementLess flexibleBuilt-in and standard

package name vs import path

ItemExampleMeaning
Import pathmyapp/commonWhere Go finds the package
Package namepackage commonName used in code after import
Usage in codecommon.Setup()Calling exported items from that package
Take Quiz

Cheat Sheet

Quick rules

  • Do not use ./common for 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

  1. Create go.mod
  2. Set a module name
  3. Import local packages as module-name/package-name
  4. 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
Take Quiz

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 common package with one exported setup function.
  • Add a routers package that returns an http.Handler.
  • Import both packages in main.go using the module path.
  • Run the app and verify it serves a response on /.
Take Quiz

Keep learning

Related questions

View more