Skip to main content
In this guide, we’ll learn about packages in Go and how to structure your code effectively.

What are packages?

A package is nothing but a directory containing one or more Go source files, or other Go packages. Every Go source file must belong to a package and package declaration is done at the top of every source file:
package <package_name>
By convention, executable programs (ones with the main package) are called Commands, while others are simply called Packages.

The Main Package

So far, we’ve done everything inside of package main. The main package should also contain a main() function which is a special function that acts as the entry point of an executable program.

Creating Custom Packages

Let’s create our own package called custom and add some source files to it such as code.go:
package custom

Imports and Exports

Just like other languages, Go also has a concept of imports and exports, but it’s very elegant.
Any value (like a variable or function) can be exported and visible from other packages if they have been defined with an uppercase identifier.
Let’s try an example in our custom package:
package custom

var value int = 10 // Will not be exported
var Value int = 20 // Will be exported
As we can see, lowercase identifiers will not be exported and will be private to the package they’re defined in. In our case, the custom package.

Importing Packages

To import and access our custom package, let’s go to our main.go file and import it. We can refer to it using the module we had initialized in our go.mod file earlier:
---go.mod---
module example

go 1.18

---main.go--
package main

import "example/custom"

func main() {
	custom.Value
}
Notice how the package name is the last name of the import path.

Multiple Imports

We can import multiple packages like this:
package main

import (
	"fmt"

	"example/custom"
)

func main() {
	fmt.Println(custom.Value)
}

Import Aliases

We can also alias our imports to avoid collisions:
package main

import (
	"fmt"

	abcd "example/custom"
)

func main() {
	fmt.Println(abcd.Value)
}

External Dependencies

In Go, we are not only limited to working with local packages. We can also install external packages using go install command as we saw earlier. Let’s download a simple logging package github.com/rs/zerolog/log:
1

Install the external package

$ go install github.com/rs/zerolog
2

Import and use the package

package main

import (
  "github.com/rs/zerolog/log"

  abcd "example/custom"
)

func main() {
  log.Print(abcd.Value)
}
Make sure to check out the go doc of packages you install, which is usually located in the project’s readme file. go doc parses the source code and generates documentation in HTML format.

Folder Structure Conventions

Go doesn’t have a particular “folder structure” convention. Always try to organize your packages in a simple and intuitive way.

Best Practices

  • Keep related functionality together in the same package
  • Use clear, descriptive package names
  • Avoid deeply nested package hierarchies
  • Group packages by functionality, not by type
  • Keep package names short and concise

Key Takeaways

  • Every Go file must declare a package at the top
  • Uppercase identifiers are exported (public)
  • Lowercase identifiers are package-private
  • The main package is special and contains the entry point
  • Import paths are based on your module path
  • External packages are managed through go modules

Build docs developers (and LLMs) love