Go, End to End
Packages and Modules
A Go module is the unit of dependency versioning, declared by a go.mod file at the root of a project. A package is a directory of .go files that share a package declaration, the unit of code organization within a module. A module can contain many packages.
go.mod and module paths
go.mod (created by "go mod init example.com/myproject")
module example.com/myproject
go 1.22
require (
github.com/some/dependency v1.4.0
)The module path doubles as the import path prefix for every package inside it. If your module is example.com/myproject, a package living in myproject/internal/parser is imported elsewhere as example.com/myproject/internal/parser. This is also why Go modules are commonly named after the repository URL they're published at: it lets go get resolve the import path directly to a place to fetch the source.
Exported vs unexported: capitalization is the access modifier
Go has no public/private/protected keywords. Whether an identifier (function, type, variable, struct field) is visible outside its package is determined entirely by whether its name starts with an uppercase letter. ParseConfig is exported and usable from other packages; parseConfig is not.
This single rule replaces three keywords' worth of access control in most other languages, and it means you can tell a lot about an API's intended surface just by scanning for capital letters.
Organizing a multi-file package
Every .go file in the same directory with the same package declaration is part of one package, and they all share the same namespace, no need to import between files in the same directory. Splitting a large package across files is purely for human readability, the compiler treats them as one unit regardless.
internal packages
Any package living in a directory literally named internal (at any depth) can only be imported by code inside the module rooted at the parent of that internal directory. This is enforced by the compiler itself, not just a naming convention. It's the standard way to expose a public API from your module while keeping implementation details unimportable from outside.
myproject/
go.mod
api/
client.go // exported API, importable by anyone
internal/
auth/
token.go // only importable by code inside myproject/Try it yourself: there's no live example for this chapter's module structure since it spans multiple files and a go.mod, which the single-file playground format can't represent. Set up a small local module with an internal/ package and confirm the compiler rejects an import of it from outside.