Packages & Go Modules

beginner go modules tooling

A package is a folder of Go files that work together. A module is a collection of packages with a version, basically one project or library. These two concepts are how Go organizes and shares code.

Let’s start small and build up.

Packages

Every Go file begins by declaring which package it belongs to.

package main // this file is part of the "main" package

The special package main is where executable programs live — it must have a func main(). Any other name (like utils or auth) is a regular library package meant to be imported by other code.

Files in the same folder must all share the same package name.

Exported vs unexported (the capitalization rule)

This is Go’s clever trick for access control, and it’s a guaranteed interview question.

In simple language: if a name starts with a capital letter, it’s public (exported). If it starts with lowercase, it’s private (unexported) to its own package.

There’s no public or private keyword. The casing is the rule.

package mathx

func Add(a, b int) int { // Capital A — exported, usable from other packages
	return a + b
}

func subtract(a, b int) int { // lowercase s — private to this package
	return a - b
}

So when we import a package and type mathx.Add(...), it works, but mathx.subtract(...) won’t even compile from outside.

Importing

We pull in other packages with import.

import (
	"fmt"          // standard library
	"strings"      // standard library
	"github.com/user/repo/auth" // a third-party or our own module's package
)

We then use the package’s last name as the prefix: fmt.Println, strings.ToUpper, auth.Login.

Modules — go mod init

A module is the unit Go uses to track dependencies and versions. We create one with:

go mod init github.com/manish/myapp

That module path is usually the repo URL where the code lives. Running this creates a go.mod file.

go.mod and go.sum

go.mod is the heart of the project. It lists the module name, the Go version, and every dependency with its version. Think of it like package.json in Node.

module github.com/manish/myapp

go 1.22

require github.com/gorilla/mux v1.8.1

go.sum is a lockfile of cryptographic checksums. It records the exact hash of each dependency so nobody can swap out a package with tampered code. Think of it like package-lock.json. We commit both files to git but never edit go.sum by hand.

Adding dependencies — go get

To add a third-party package:

go get github.com/gorilla/mux

This downloads it and updates go.mod and go.sum automatically. To clean up unused deps and add any missing ones, run:

go mod tidy

go mod tidy is the one we run before committing — it keeps go.mod honest.

Building and running — go build vs go run

go run main.go   # compile + run in one step, no file left behind. Great for dev.

go build         # compile into a binary in the current folder. Doesn't run it.
./myapp          # then we run the binary ourselves

go run is for quick iteration. go build is for producing the actual binary we ship.

GOPATH is dead

Worth knowing if we read old tutorials. Years ago, all Go code had to live inside one magic folder called $GOPATH/src, and dependency management was a mess.

Since Go 1.11+, modules replaced GOPATH. Now our project can live anywhere on disk — we just need a go.mod file. If a tutorial tells us to set up GOPATH, it’s outdated.

Interview soundbite

Go organizes code into packages (a folder of files) and modules (a versioned project). Access control is done purely by capitalization — capitalized names are exported/public, lowercase ones are private to the package. A module is created with go mod init, tracked in go.mod (like package.json) and go.sum (a checksum lockfile), and the old GOPATH model has been dead since modules arrived in Go 1.11.