Chapter 8: Packages & Modules
In this chapter, you’ll learn how Go organizes code using packages and modules. We’ll explore how to create, import, and manage them so you can structure your projects cleanly and reuse code efficiently.
What You Will Learn
By the end of this chapter, you will understand:
- How to create and organize your own packages
- The difference between exported and unexported identifiers
- How importing packages works in Go
- How the Go module system manages dependencies
- Semantic versioning in Go module ecosystem
- Best practices for folder structure and project layout
This chapter teaches how Go projects scale from a single file to full applications.
8.1 What Is a Package?
In Go, a package is a group of related files grouped under the same folder and namespace.
Every .go file begins with:
package mainor another package name like:
package mathutilsThe main Package
A special package — it defines the entry point of a program.
It must contain:
func main() {}Example:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}Other packages cannot define main() unless they are meant to be executable.
8.2 Creating Your Own Package
Let’s create a simple reusable package.
Get Aditya Rathore’s stories in your inbox
Join Medium for free to get updates from this writer.
Folder structure:
myapp/
├── main.go
└── mathutils/
└── add.goFile: mathutils/add.go
package mathutils
func Add(a, b int) int {
return a + b
}File: main.go
package main
import (
"fmt"
"myapp/mathutils"
)
func main() {
fmt.Println(mathutils.Add(3, 4))
}8.3 Exported vs Unexported Identifiers
Go uses capital letters (not keywords) to control visibility:
| Identifier Style | Scope |
| ---------------- | ----------------------------------- |
| Add | Exported (public) |
| add | Unexported (private within package) |Example:
package mathutils
// Exported
func Add(a, b int) int { return a + b }
// Unexported
func subtract(a, b int) int { return a - b }Attempting to call subtract outside the package will fail.
8.4 Importing Packages
Import built-in packages:
import "fmt"Import external packages:
import "github.com/google/uuid"Import multiple packages using parentheses:
import (
"fmt"
"math"
)Aliasing Imports
import u "github.com/google/uuid"
fmt.Println(u.New())Blank Import (Run init() only)
Used when a package must initialize but not be referenced:
import _ "database/sql/driver"8.5 The Go Module System
Modern Go (1.16+) uses modules for dependency management.
Initialize a module:
go mod init myappThis creates:
go.modExample go.mod file:
module myapp
go 1.21To download dependencies:
go mod tidy8.6 Versioning in Modules
Go uses semantic versioning:
major.minor.patchExample dependency entry:
require github.com/google/uuid v1.3.0The Go ecosystem resolves and caches modules:
go list -m allUpdate packages:
go get -u ./...8.7 Package Layout & Best Practices
As projects grow, structure matters.
Recommended layout:
myproject/
├── cmd/
│ └── myapp/ # main entry
│ └── main.go
├── internal/ # private reusable code
├── pkg/ # reusable library code
├── api/
├── go.mod
└── go.sumBest Practices:
✔ Small focused packages
✔ Avoid circular imports
✔ Export only what is necessary
✔ Keep names meaningful and concise
✔ Group files by domain, not file type
Summary of Chapter 8
You now understand:
✔ How to create packages
✔ How export visibility works using lowercase/uppercase
✔ How to import built-in and external packages
✔ How the Go module system manages dependencies
✔ Module versioning and upgrades
✔ Best practices for Go project structure








