-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
This is a feature request for the default behavior of the go mod init
command (doc, ref).
Background
This command creates a go.mod file for a new module, initialized with two directives: module
and go
. The module path, a part of the module
directive, is provided explicitly to go mod init
via an argument in many cases. The version used in the go
directive is not explicitly specified by the user, and so its value is currently inferred from the currently selected version of the Go toolchain. For example:
$ cd $(mktemp -d)
$ go mod init example.com # using go version go1.25rc2
go: creating new go.mod: module example.com
$ cat go.mod
module example.com
go 1.25rc2
The go command has no good way of knowing what value of the go
directive the user intends to use in the module being created eventually, so when picking an initial value for it, it uses a simple heuristic: "the latest version supported by this toolchain".
This behavior has a property of being simple, predictable, and importantly, it can work while completely offline (i.e., no internet connection required).
Feature Request
I suggest changing the initial default version to the following behavior:
- if the current toolchain version is a stable version of Go 1.N.M, default to
go 1.(N-1).0
- if the current toolchain version is a pre-release version of Go 1.N (Release Candidate M) or a development version of Go 1.N, default to
go 1.(N-2).0
Using version types as defined here. This behavior maintains the property of being able to work offline. While more complex and less predictable, it is still fairly simple.
Examples of the new behavior:
$ cd $(mktemp -d)
$ go mod init example.com # using go version go1.25rc2
go: creating new go.mod: module example.com
$ cat go.mod
module example.com
go 1.23.0
$ cd $(mktemp -d)
$ go mod init example.com # using go version go1.24.5
go: creating new go.mod: module example.com
$ cat go.mod
module example.com
go 1.23.0
(Edit: The go work init
command also chooses an initial value for its go directive, and so it likely makes sense to have it continue to follow what go mod init
does.)
Motivation
The motivation of adopting the new default value is to provide what should be a better initial value of the go
directive in most cases, especially for cases where the user will choose not to pick a different value. Per the Go release policy, we support the two most recent major releases of Go, so provided one of those is used during go mod init
, the new default value will never cut off one of the currently supported Go toolchains.
It's still a heuristic and is imperfect: if someone's using a supported Go toolchain like Go 1.23.11, its go mod init
would pick go 1.22.0
while it could also pick go 1.23.0
without cutting off a currently supported Go toolchain. It's not a goal of this feature request to add further complexity to avoid that. Ultimately the user will be able to do go get go@{desired version}
whenever the default needs to be changed. This also applies to modules that only provide commands, not packages to be imported by others, where the user may intentionally wish to require a newer major Go version. As for why ".0" and not a newer minor release, motivation is similar to Why not bump on each minor release? of a past proposal, and because it can be done without needing internet.
Alternatives
The go get command supports version query latest
and patch
. For example, go get go@latest
or go get go@patch
. If there was another query added, something that would resolve to "oldest supported major release", and if it were desirable for go mod init
to resolve it over the internet, then that query could be reused. I considered this but decided the simpler, query-free path should be a better place to start with. This is still something that can be done in the future if desired.
CC @golang/command-line.