go mod init — Specification¶
Table of Contents¶
- Introduction
- Where
go mod initIs Specified - Synopsis
- Module Path Syntax
- The
go.modFile: Grammar - The
moduleDirective - The
goDirective - Auto-Detection of Module Path
- Module Path Validation Rules
- Major Version Suffix Rule
- What
go mod initDoes NOT Do (Per Spec) - Differences Across Go Versions
- References
Introduction¶
The Go language specification (go.dev/ref/spec) does not specify go mod init. The command is part of the tooling, not the language. The authoritative reference is the Go Modules Reference at go.dev/ref/mod, which is maintained alongside the toolchain source.
This file separates "what the modules reference says" from convention and tooling behaviour. Where the reference is silent, the toolchain source code (cmd/go/internal/modcmd/init.go) is the de-facto specification.
References: - Go Modules Reference - go help mod init - The go.mod file
Where go mod init Is Specified¶
go mod init is documented in two places officially:
go help mod init— terse, command-line oriented.- Go Modules Reference, Section "Initializing a new module" — detailed.
The output of go help mod init:
usage: go mod init [module-path]
Init initializes and writes a new go.mod file in the current directory,
in effect creating a new module rooted at the current directory. The
go.mod file must not already exist.
Init accepts one optional argument, the module path for the new module.
If the module path argument is omitted, init will attempt to infer the
module path using import comments in .go files, vendoring tool
configuration files (such as Gopkg.lock), and the current directory
(if in GOPATH).
If a configuration file for a vendoring tool is present, init will
attempt to import module requirements from it.
See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
That is the official text. Everything else flows from the modules reference and the source.
Synopsis¶
module-pathis optional; when omitted, the command attempts auto-detection.- Exit code 0 on success, non-zero on validation or I/O error.
- Output: a confirmation line on stderr; a newly-created
go.modfile in the current directory.
Module Path Syntax¶
Per the Go Modules Reference (section Module paths), a module path is a sequence of components separated by /. Each component must conform to the following grammar:
ModulePath = PathComponent { "/" PathComponent } [ MajorVersion ] .
PathComponent = letter { letter | digit | "-" | "." | "_" | "~" } .
MajorVersion = "/v" digit { digit } . // Required for major >= 2.
letter = lowercase ASCII letter | digit | one of [.-_~].
^^^ first char of the first component must be a letter or digit
(Simplified; the actual grammar is in the source of golang.org/x/mod/module.)
Concrete rules:
- The path must contain at least one component.
- The first component must contain a dot (for non-local module paths).
- Each component is non-empty.
- Each component contains only ASCII lowercase letters, digits, and the punctuation
. - _ ~. - No path component is
.or... - Trailing slashes are forbidden.
- The path must not exceed 256 bytes.
- If the major version is 2 or greater, the last component must be
vNwhereNis the major version.
The go.mod File: Grammar¶
The grammar of a go.mod file (informal, per Go Modules Reference):
GoMod = { Directive } .
Directive = ModuleStmt | GoStmt | ToolchainStmt | RequireStmt | ReplaceStmt
| ExcludeStmt | RetractStmt | GodebugStmt | Comment .
ModuleStmt = "module" QuotedString .
GoStmt = "go" Version .
ToolchainStmt = "toolchain" ToolchainName .
RequireStmt = "require" ( ModuleVersion | "(" { ModuleVersion } ")" ) .
ReplaceStmt = "replace" ModuleVersion "=>" ModuleVersion .
ExcludeStmt = "exclude" ModuleVersion .
RetractStmt = "retract" ( Version | VersionRange | "(" { Version } ")" ) .
GodebugStmt = "godebug" GodebugSetting .
ModuleVersion = ModulePath [ Version ] .
Version = "v" Number "." Number "." Number [ "-" PreRelease ] [ "+" Build ] .
A fresh go.mod from go mod init contains exactly:
— in that order, separated by a blank line.
The module Directive¶
Quoting:
- The path may be unquoted if it contains only the safe characters (letters, digits,
/,.,-,_,~). - Otherwise it must be enclosed in double quotes. (This is rare; the safe set covers all valid paths.)
Number of module directives per file: exactly one.
A missing module directive is an error: the file is not a valid go.mod.
The go Directive¶
Where <version> is one of:
1.N— major.minor1.N.P— major.minor.patch (legal but uncommon for thegodirective)
Semantic rules:
- Indicates the minimum Go language version required by this module.
- The toolchain refuses to compile a module whose
godirective exceeds the running toolchain's version. - Since Go 1.21, the directive also affects some library behaviours via the language version selection mechanism (see
runtime/debug.SetGCPercentsemantics,for-loop variable semantics, etc.).
Number of go directives: exactly one.
A missing go directive is, since Go 1.17, treated as an implicit go 1.16 and prints a warning.
Auto-Detection of Module Path¶
When the user runs go mod init without an argument, the command's auto-detection logic runs in this order (per cmd/go/internal/modcmd/init.go and cmd/go/internal/modload/init.go):
- Existing
go.modupward. If ago.modis found in any ancestor directory, init refuses (you are inside another module). // importcomments in.gofiles. Specifically, the toolchain reads the first.gofile and looks for a comment of the form: If found, that path is used.- Legacy lockfiles. Files left by old vendoring tools —
Gopkg.lock,glide.yaml,vendor.conf,vendor.json— may contain a module path. The toolchain extracts it. $GOPATH/srclocation. If the current directory is under$GOPATH/src/<X>, the path defaults to<X>.- Failure. If none of the above succeed, return an error:
cannot determine module path for source directory ....
There is no Git remote inspection in the public toolchain (despite folklore). The git URL of the working directory is not consulted by go mod init itself.
Module Path Validation Rules¶
The path passed to go mod init is validated by golang.org/x/mod/module.CheckPath. The rules:
// From golang.org/x/mod/module:
func CheckPath(path string) error {
// Each path element separately validated:
// 1. non-empty
// 2. begins with letter or digit
// 3. uses only allowed characters
// 4. no consecutive dots
// 5. no leading dot in element
// 6. last element may be a major-version suffix
// Whole path:
// 1. <= 256 bytes
// 2. first element contains a dot (for non-local paths)
// 3. no Windows-reserved names
}
Examples of valid paths:
github.com/alice/libexample.com/testlib.example.com/csvkitexample.com/lib/v2example.com/lib/sub/v3
Examples of invalid paths:
github.com/Alice/Lib(uppercase)lib(no dot in first element — accepted but treated as local-only)github.com//lib(empty component)github.com/.lib(leading dot)github.com/lib/v0(v0 suffix is not allowed; onlyv2+)github.com/CON/lib(Windows-reserved nameCON)
Major Version Suffix Rule¶
For modules with major version 2 or greater, the path must end with /vN. The rule from the Go Modules Reference:
A module that has been declared at major version 2 or higher must have a major version suffix at the end of its path. This requirement implements the import compatibility rule: any two versions of a module that have the same import path must be backwards compatible.
Examples:
| Major version | Required path suffix |
|---|---|
| v0.x.x or v1.x.x | none |
| v2.x.x | /v2 |
| v3.x.x | /v3 |
| ... | ... |
/v0 and /v1 are explicitly forbidden suffixes. /v2 is the smallest allowed.
Within a go.mod file, the module directive must agree with the tag major version of the surrounding repository for releases to be discoverable.
What go mod init Does NOT Do (Per Spec)¶
The Go Modules Reference is explicit about scope:
- It does not download dependencies.
- It does not resolve a module graph.
- It does not contact the network.
- It does not initialize a VCS repository.
- It does not create directories.
- It does not create
go.sum(which is created bygo getorgo mod tidy). - It does not enforce that the path corresponds to a real network resource.
Conversely, behaviours that are spec'd:
- Refusal if
go.modexists. - Validation of the supplied path against
module.CheckPath. - Auto-detection in the order described above.
- Writing
moduleandgodirectives, in that order.
Differences Across Go Versions¶
The behaviour of go mod init has evolved:
- Go 1.11 — Modules introduced as opt-in, behind
GO111MODULE=on.go mod initrequires the env var. - Go 1.13 — Module proxy and sum DB introduced.
go mod initis unchanged but downstream operations begin using them. - Go 1.14 —
vendor/becomes auto-detected when present and-mod=vendornot specified. - Go 1.16 — Modules become the default;
GO111MODULE=onno longer required outside GOPATH. - Go 1.17 —
go.moddirective parsing strengthened; missinggodirective treated as implicitgo 1.16. - Go 1.18 — Workspaces introduced (
go.work).go mod initunaware of workspaces. - Go 1.19 — Minor improvements to error messages.
- Go 1.21 —
toolchaindirective added.godirective's semantics expanded (language version selection). - Go 1.22 —
for-loop variable semantics tied togodirective value. - Go 1.23 —
range-over-func iterators tied togodirective value.
The mechanical command — go mod init <path> writes a two-directive go.mod — has not changed since Go 1.11. The semantics of the directives it writes have grown.