Every Go file belongs to a package, declared on its first line. Code in one package uses another by importing it and prefixing names with the package name. Only names that start with a capital letter can be used from outside the package.
fmt, math and strings are standard library packages. They ship with Go, so "adding" one means writing its name in the import block. Nothing is downloaded. fmt.Println, math.Sqrt and strings.Repeat are capitalized because they are exported.
The Package Clause
The first non-comment line of every .go file is package name. All files in one directory must use the same name, and together they form one package. A directory with two different package names does not compile:
found packages greeting (b.go) and greet (greet.go) in /home/ana/shop/greet
(The one exception is test files, which may use package name_test.)
package main is special: it produces an executable, and the program starts at its func main(). Every other package is a library meant to be imported.
By convention the package name matches the last element of the directory path: code in shop/greet is package greet. Package names are short, lowercase, single words, with no underscores or mixed caps: strconv, httptest, greet, not string_utils or greetHelpers.
Importing Packages
An import path is a string. For the standard library it is the package's path under Go's source tree; for everything else it starts with a module path:
import (
"fmt" // standard library
"net/http" // standard library, nested path
"math/rand/v2" // standard library, version 2 of math/rand
"github.com/google/uuid" // another module (needs go get)
"example.com/shop/greet" // a package in your own module
)
The path is where the package lives; the name is what you type in code. For net/http the name is http, for math/rand/v2 it is rand. You write http.Get, never net/http.Get.
gofmt and goimports sort the block and conventionally separate standard library imports from the rest with a blank line.
Unused imports are a compile error:
./main.go:5:2: "os" imported and not used
Editors with Go support run goimports on save, which adds missing standard imports and removes unused ones for you.
Exported vs Unexported Names
Visibility in Go is decided by one rule: if a name starts with an uppercase letter, it is exported. That applies to functions, types, variables, constants, struct fields and methods. There are no public, private or protected keywords.
| Name | Visible outside the package? |
|---|---|
func Hello() | yes |
func hello() | no |
type User struct | yes |
User.Name field | yes |
User.email field | no |
const MaxSize | yes |
var defaultTimeout | no |
Trying to use an unexported name from another package gives an undefined error:
./main.go:11:20: undefined: greet.prefix
The rule matters even inside a single file, because other packages inspect your types. encoding/json can only see exported fields:
token is left out of the JSON, silently. That is a feature when the field is private data and a surprise when you forgot to capitalize a field you wanted.
Splitting a Package Across Files
A package can span as many files as you like. Every file in the directory with the same package line sees every name declared in the others, exported or not, without importing anything:
shop/
├── go.mod (module example.com/shop)
├── main.go
└── math.go
// main.go
package main
import "fmt"
func main() {
fmt.Println(total(2, 3))
}
// math.go
package main
func total(a, b int) int { return a + b }
main.go calls total directly. There is no #include and no import between files of the same package.
The "undefined" error from go run main.go
This is the most searched package problem in Go, and it has one cause. Running only the file that contains main compiles only that file:
go run main.go
# command-line-arguments
./main.go:6:14: undefined: total
command-line-arguments is the name Go gives to a package built from a list of files, and math.go is not in that list. Run the whole package instead:
go run .
5
The same applies to go build main.go. Use go run . and go build (or go build ./cmd/app) and the problem never appears. If it persists with go run ., check that both files say package main and that neither has a build constraint (//go:build) or a _test.go suffix excluding it.
Your Own Packages
A subdirectory of your module is a separate package. Import it with the module path from go.mod plus the directory:
shop/
├── go.mod (module example.com/shop)
├── main.go
└── greet/
└── greet.go
// greet/greet.go
package greet
const prefix = "Hi, "
// Hello returns a greeting for name.
func Hello(name string) string {
return prefix + name
}
// main.go
package main
import (
"fmt"
"example.com/shop/greet"
)
func main() {
fmt.Println(greet.Hello("Ana"))
}
Hi, Ana
Two things trip people up here. The import is the module path plus directory, not a relative path: "./greet" does not work in module mode. And prefix stays hidden from main because it is lowercase; only Hello is part of the package's API.
Internal Packages
A directory named internal restricts who can import what is inside it. Code in shop/internal/store can be imported by any package rooted at shop/, and by nothing outside it. Another module that tries gets:
use of internal package example.com/shop/internal/store not allowed
Use internal/ for code you want to share between your own packages without promising it to the rest of the world. You can change its API freely, since no outside code can depend on it.
Import Aliases
Give an import a different local name by writing the name before the path. The usual reason is two packages with the same name:
Both packages are called rand, so at least one needs an alias. Use aliases for conflicts and for names that are unclear; do not rename packages just to shorten them, since readers know strconv and not your sc.
Blank and Dot Imports
Blank import (_). Imports a package only for its side effects: its package variables and init functions run, but you use none of its names. Database drivers and image decoders register themselves this way:
import (
"database/sql"
_ "github.com/lib/pq" // registers the "postgres" driver with database/sql
)
Without the _, the import would be an unused-import error.
Dot import (.). Puts the package's exported names directly into your file's scope, so you write Println instead of fmt.Println. It hides where names come from and is discouraged outside a few test helper patterns.
Import Cycles
Go does not allow two packages to import each other, directly or through a chain:
package example.com/shop
imports example.com/shop/greet from main.go
imports example.com/shop/other from c.go
imports example.com/shop/greet from o.go: import cycle not allowed
The error lists the chain. Two fixes cover almost every case:
- Move the code both packages need into a third, lower-level package that both import.
- If package A only needs to call something in B, define a small interface in A and let B's type satisfy it. A no longer imports B.
A cycle usually means the package boundaries are drawn around layers of code that actually belong together, so it is also a signal to reconsider the split.
Common Mistakes
- Running a single file.
go run main.goin a multi-file package: usego run .. - Relative imports.
import "./utils"fails in module mode. Use"example.com/yourmodule/utils". - Lowercase names you meant to export. A function, field or method that other packages need must start with a capital letter.
- Package name that does not match the directory. Legal, but confusing: the import path says
utilsand the code sayshelpers.X. Keep them the same. - Catch-all package names.
util,commonandmiscsay nothing about their contents and tend to grow into import-cycle magnets. Name packages after what they provide:money,auth,slug.
Frequently Asked Questions
Why does Go say a function in the same package is undefined?
You probably ran go run main.go. Naming a file compiles only that file, so functions defined in other files of the same package are missing: undefined: total. Run go run . instead, which compiles every .go file in the directory. Also check that every file has the same package line.
How do I add the fmt package in Go?
fmt is part of the standard library and ships with Go, so there is nothing to install. Add import "fmt" after the package line and call its functions with the fmt. prefix, for example fmt.Println("hi"). The same goes for strings, os, time, net/http and every other standard package.
How do I import my own package in Go?
Import it by module path plus directory. In a module named example.com/shop, a package in the greet folder is imported as import "example.com/shop/greet" and used as greet.Hello(). Only names starting with a capital letter are visible to the importer.
What is the difference between exported and unexported in Go?
A name that starts with an uppercase letter (Hello, Total, User.Name) is exported and can be used from other packages. A lowercase name (hello, total, user.name) is unexported and visible only inside its own package. There are no public or private keywords.
How do I fix "import cycle not allowed" in Go?
Two packages import each other, directly or through a chain, which Go forbids. Move the shared code into a third package that both import, or define a small interface in the package that needs the behavior so it no longer imports the other one.