Master

Modules and Packages

Organize code into modules and reusable packages.

What you will see

5 42

About 1 min of reading

Try It

You will organize a small project into a module with two packages, see how exported names are imported and used, and watch the build link both packages together.

1

I create a package that holds a single exported function, Add. Exporting means the first letter is uppercase, so other packages can import and call it.

package mathutil func Add(a, b int) int { return a + b }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
package builds cleanly
2

I write the main package that imports the mathutil package and calls Add. The import path points at the package inside the module.

package main import ( "fmt" "example.com/app/mathutil" ) func main() { fmt.Println(mathutil.Add(2, 3)) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
5
The import path matches the module path plus the package directory, so module example.com/app with a mathutil folder gives example.com/app/mathutil.
3

I change the numbers and run again to confirm the call produces a new result. The function logic does not change, only the values it receives.

package main import ( "fmt" "example.com/app/mathutil" ) func main() { fmt.Println(mathutil.Add(10, 5)) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
15
4

I try to call helper, a function that is unexported. The compiler refuses, so I see how exported names are the only ones that cross package boundaries.

package main import ( "fmt" "example.com/app/mathutil" ) func main() { fmt.Println(mathutil.helper()) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
example.com/app\n.\main.go:9:26: undefined: mathutil.helper
Names that start lowercase stay private to their package. Rename helper to Helper to export it, then the call compiles.
5

I export a second function, Mul, and use both Add and Mul in one program. The build links both into the final output, printed in order.

package main import ( "fmt" "example.com/app/mathutil" ) func main() { fmt.Println(mathutil.Add(2, 3)) fmt.Println(mathutil.Mul(6, 7)) }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
5 42

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A module groups packages; imported packages expose exported symbols.
1 Define a module with go.mod
↓
2 Create packages inside it
↓
3 Export functions and types
↓
4 Other code imports the package
Why this works
The go.mod file

go.mod is the module manifest:

module example.com/myapp
go 1.22
require github.com/x/y v1.2.3

It pins the module path, the Go version, and required dependencies with their exact versions.

Package conventions

Follow Go package conventions:

  • One package per directory
  • Package name matches the directory
  • Export only what other code needs

package utils

func helper() {}

Clean boundaries make code readable and testable.

Examples

Initializing a module

Setting up a project

go mod init example.com/myapp

A module is a collection of packages tracked together. go.mod records the module path and dependencies.

Why it works: modules give Go its dependency management and versioning.

Exporting packages

Public vs private

// mathutil/mathutil.go
package mathutil

func Add(a, b int) int { return a + b }  // exported

func helper() int { return 0 }            // unexported

Names starting with an uppercase letter are exported and importable. Lowercase names stay private to the package.

Why it works: Go uses capitalization, not keywords, for access control.

Managing dependencies

Adding libraries

go get github.com/stretchr/testify
go mod tidy

go get downloads a dependency; go mod tidy cleans up unused entries. Versions are locked in go.sum for reproducible builds.

Why it works: the module cache and checksums keep builds deterministic.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← JSON and Structs
Previous Lesson
JSON and Structs
Next Lesson
Testing
Testing →