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.

Comment From: seankhliao

Given that language features, and compatibility settings are gated on the go directive, I think this is a worse default, as starting out with a latest toolchain, you wouldn't be able to use the latest features without manually updating the go version. Setting it as default would also mean the default experience is to have editor / vet warnings for using standard library packages and functions of the toolchain you have installed.

Wanting to support a previous release should be a conscious choice.

Comment From: dmitshur

Yes, that is intentional. The go directive sets both the semantics of the module and the minimum version required to use it. If someone has a need to rely on recently added features or semantics, they'd need to explicitly select the version.

I'm suggesting the inverse: if a user goes all the way from creating a module locally to publishing it for consumption by other users, and does not explicitly change the go directive from the value that go mod init chose, I think it being initialized to 1.(N-1).0 should lead to a better outcome. It means any other module whose minimum version requirement is already a supported Go version will be able to require the newly published module without involving a go directive increase.

Comment From: gabyhelp

Related Issues

Related Code Changes

Related Documentation

Related Discussions

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: mvdan

I agree with this proposal. Most modules I write don't need to require the very latest Go language version, and most of the modules I maintain tend to support two versions.

Plus, since I daily drive tip, I practically always have to fix up a module after go mod init if I want it to work anywhere else.