Skip to content

Packages & Modules

Every Go file belongs to a package, declared at the top:

package geometry

A directory is a package — every .go file in it must declare the same package name. Group related code the way you’d group files in any language: geometry, httpclient, storage, and so on.

Go uses a simple, capitalization-based visibility rule — no public/private keywords:

func Area(r Rectangle) float64 { ... } // exported (capital A) — usable from other packages
func area(r Rectangle) float64 { ... } // unexported (lowercase a) — package-private

This applies to functions, types, struct fields, and constants alike.

A module is a collection of packages versioned and distributed together. go.mod declares the module path and its dependencies:

module example.com/myapp
go 1.23
require (
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
)

Add a dependency by importing it and running:

Terminal window
go get github.com/spf13/cobra@v1.8.1
go mod tidy # cleans up unused/missing entries

go.sum records cryptographic checksums of every dependency, so builds are reproducible and tamper-evident — commit both files.

import "example.com/myapp/internal/geometry"

The special internal/ directory is enforced by the compiler: packages under internal/ can only be imported by code inside the same module tree, which is Go’s built-in way to mark something “for internal use only.”

A common (not mandatory) layout for a service:

myapp/
├── go.mod
├── main.go
├── internal/
│ ├── storage/
│ └── httpapi/
└── pkg/
└── geometry/ # ok for other modules to import

internal/ for implementation details, pkg/ (or the module root) for anything meant to be a public API.