go.mod Reference
Purpose and Scope
A go.mod file is the module manifest for a Go module. It records the module path, the Go language version expected by the module, and the dependency requirements that the go command uses when loading, building, testing, and editing packages. The public Go documentation describes go.mod as the file generated by go mod init and then maintained by commands such as go get, go mod tidy, and go mod edit. This page is a reader-facing reference for the directives that appear in that file and for the workflow the command-line tools expect around it.
The important rule for everyday development is that go.mod is not just a free-form note to other humans. It is input to the module-aware go command. When you import a package, run a build, or run tests, the command interprets module metadata to decide which module versions make up the build list. The official tutorial flow starts by creating a directory, running go mod init example.com/hello, and then importing packages by their full package paths. That workflow teaches the core relationship: the module path in go.mod is the prefix for packages in the module, while dependencies are named by module path and version.
The repository evidence supplied for this page shows how Go-tree command-line programs present flags, help text, validation, and executable examples. The vendored pprof driver defines command metadata with descriptions and usage text, and its CLI parser registers flags, accepts positional sources, and returns structured input to later execution. The database/sql CLI example shows a conventional Go command-line program parsing flags, validating required input, using environment defaults, and performing work under cancellable contexts. Those patterns are useful when reading go mod documentation because module operations are invoked as command-line workflows with explicit arguments and tool-managed state.
Sources: src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go, src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go, src/database/sql/example_cli_test.go
Relevant Source Files
src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go- Defines a command table, per-command descriptions, usage text, and extension hooks in a Go-tree command-line tool. It grounds the way command references in this repository describe actions, parameters, and help output.src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go- Shows command-line flag registration, parsing, default values, positional argument handling, and validation in a bundled Go tool. It supports the CLI-oriented parts of this reference:go modoperations are likewise invoked through named commands and flags.src/database/sql/example_cli_test.go- Provides a concrete executable example that parses flags, reads an environment default, validates required inputs, creates a resource handle, defers cleanup, and uses contexts for bounded work. It is useful as a model for writing module-based commands that are then described bygo.modmetadata.
Core Directives
The module directive names the current module. Its value is a module path, commonly a repository-root path such as example.com/mymodule or example.com/hello. The module path should identify where the module can be downloaded by Go tools, and it also forms the import-path prefix for packages inside the module. If the module path is example.com/hello, a package in a subdirectory named internal/report would be imported as example.com/hello/internal/report when it is importable from the caller. A module version and module path together uniquely identify a released module version.
The go directive records the minimum Go version required by the module. It affects how the command interprets language and module behavior for the module, so it should be updated intentionally rather than treated as a comment. A newly initialized module receives a go.mod with the current module path and an appropriate go directive. In normal workflows, developers let the go command maintain the file while they focus on imports and package code; manual edits are possible, but command-assisted edits help preserve valid syntax and consistent requirements.
The require directive lists module dependencies and the minimum versions needed by the current module. It can appear once per dependency or in a parenthesized block. Requirements are module-level facts, not package-level imports, so a single required module can provide several packages. The go command computes a build list from the main module requirements and their transitive requirements, then selects versions according to module rules. In practical terms, if source code imports a package from another module, the corresponding module requirement must be present either directly or through command-managed dependency resolution.
The replace directive tells the go command to substitute one module path and optional version with another module version or with a local directory. This is especially useful while following the official tutorial pattern of creating a library module beside a caller module. A caller can require the library module path it imports, then replace that module path with a local relative directory during development. The import path remains stable in source code, while the resolver is redirected to the developer checkout. Replacements are local build instructions and should be reviewed carefully before publishing a module intended for others.
The exclude directive prevents a specific module version from being used. It is less common than require and replace, but it gives the main module a way to rule out a known-bad version when version selection would otherwise consider it. Public Go documentation also describes module-file instructions for replacing required modules, excluding versions, and ignoring specific directories when matching package patterns. Because module behavior evolves across Go releases, use go help mod, go help mod edit, and the current Go modules reference for version-specific directive details beyond the common directives summarized here.
Example go.mod Layout
A compact go.mod file usually starts with the current module path and the Go version, followed by dependency requirements. The official go.mod reference uses examples shaped like the following. The parenthesized require block is equivalent to multiple single-line requirements, but it is easier to read when a module has more than one dependency. A replace directive may point one dependency to a local sibling directory during development, which is the same conceptual workflow used when a tutorial caller module imports code from a locally created library module.
module example.com/mymodule
go 1.22
require (
example.com/othermodule v1.2.3
example.com/thismodule v1.2.3
example.com/thatmodule v1.2.3
)
replace example.com/thatmodule => ../thatmodule
exclude example.com/thismodule v1.3.0The values in this file describe modules, not arbitrary source directories. example.com/thatmodule is the dependency identity used by imports and requirements, while ../thatmodule is a local filesystem location substituted by the main module. If the local replacement contains packages, their package import paths still begin with the replaced module path. That separation is important: source imports should usually name stable module paths, while the replace directive handles temporary local routing. Removing the replacement later should not require rewriting package imports if the published module path is the same.
Command Workflow and Interpretation
The normal entry point is go mod init MODULEPATH, which creates a new go.mod file for the current directory. In the tutorial sequence, the caller module uses go mod init example.com/hello before writing a main package that imports example.com/greetings and fmt. The main package makes the directory buildable as an application, while the imports declare package dependencies in source. The module file then gives the go command the metadata it needs to resolve non-standard-library imports. This is why module setup happens before the first module-aware build or run.
After initialization, dependency edits are usually made through commands. go get changes dependency versions, go mod tidy reconciles requirements with imported packages and tests, and go mod edit provides explicit structured edits. This command-driven style mirrors the CLI source evidence: the pprof driver builds a registry of commands with descriptions and usage strings, and its parser converts flags and positional arguments into a structured source value before later execution. For module workflows, the go command performs the same broad kind of responsibility: parse user intent, validate arguments, update structured state, and report actionable errors.
Sources: src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go, src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
A developer should also understand when go.mod is read. Running go build, go test, go run, or go list in module mode causes the command to locate the main module, read the module file, and load packages using the resulting module graph. If imports introduce new dependencies, modern Go commands may suggest or perform updates depending on the operation and mode. Because the module file is shared source metadata, teams normally review changes to it the same way they review code changes. Unexpected version bumps, added replacements, or retained excludes can change builds for every developer using the module.
The database/sql example in the repository demonstrates a pattern that also applies to module-aware command programs: parse configuration, validate required inputs, initialize resources, defer cleanup, and use contexts for bounded execution. Its Example_openDBCLI reads flags, verifies that the data source name and ID are present, opens a handle, configures connection pooling, and then runs work through cancellable contexts. A Go program built from a module does not need database/sql, but the example shows the style of command-line application that a go.mod file commonly supports: a reproducible module boundary around code that can be built, tested, and installed.
Sources: src/database/sql/example_cli_test.go
Compact Directive Reference
| Directive | Common form | What it means | Typical command interaction |
|---|---|---|---|
module | module example.com/mymodule | Declares the identity and package-path prefix of the current module. | Created by go mod init; rarely changed after publication. |
go | go 1.22 | Records the Go version expected by the module. | Added at initialization and updated intentionally as the project raises its minimum Go version. |
require | require example.com/lib v1.2.3 | Adds a minimum required module version to the module graph. | Managed by go get, go mod tidy, and imports discovered by module-aware commands. |
replace | replace example.com/lib => ../lib | Redirects a module path, optionally at a version, to another version or local directory. | Used for local development, forks, and temporary substitution. Review before publishing. |
exclude | exclude example.com/lib v1.2.4 | Prevents a specific module version from being selected by the main module. | Used sparingly when a version must not participate in builds. |
This table is intentionally compact, but each entry carries a different kind of stability promise. module and package imports are part of the public shape of a module once published. go communicates the language and tooling baseline. require expresses dependency minimums that may be pruned or adjusted by tooling. replace and exclude are main-module instructions, so they affect local builds but do not become transitive requirements for downstream users in the same way ordinary dependency metadata does. Treat them as build-environment policy rather than as an API surface exported to every importer.
Practical Review Checklist
When reviewing a go.mod change, first check whether the module path still matches the intended import path. A mismatch is often more expensive than an ordinary version issue because source imports throughout downstream projects may depend on that path. Next, check whether the go directive was changed deliberately and whether the project is ready to require that version. Then inspect added or removed require lines: a new import can legitimately add a dependency, but a surprising version jump or downgrade deserves a look at why the command selected it.
Review replace directives with extra care. They are powerful during local multi-module development, but a replacement to ../somewhere only works for developers with the same local layout. If a project is meant to be consumed publicly, keep local replacements out of release commits unless the repository has an intentional policy for them. Review exclude directives by asking whether the excluded version is still relevant and whether comments, issue links, or release notes elsewhere explain the reason. A stale exclusion can confuse later maintainers even when it remains syntactically valid.
Finally, prefer go commands over hand-editing when possible. Manual edits can be appropriate for small, clear changes, but the command has the context needed to keep the file valid and consistent with imports. Use go mod tidy before committing dependency cleanup, use go list or go test to verify package loading, and read go help mod for the command-specific behavior of the Go version you are using. For the conceptual background behind this reference, continue with Modules Overview, Managing Dependencies, and Multi-Module Workspaces.