Sitemap
Aditya Rathore

Aditya Rathore

Chapter 8: Packages & Modules

3 min readNov 24, 2025

--

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.

Press enter or click to view image in full size

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 main

or another package name like:

package mathutils

The 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.go

File: 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 myapp

This creates:

go.mod

Example go.mod file:

module myapp

go 1.21

To download dependencies:

go mod tidy

8.6 Versioning in Modules

Go uses semantic versioning:

major.minor.patch

Example dependency entry:

require github.com/google/uuid v1.3.0

The Go ecosystem resolves and caches modules:

go list -m all

Update 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.sum

Best 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

--

--