| --- |
| title: "Go Toolchains" |
| layout: article |
| --- |
| |
| ## Introduction {#intro} |
| |
| Starting in Go 1.21, the Go distribution consists of a `go` command and a bundled Go toolchain, |
| which is the standard library as well as the compiler, assembler, and other tools. |
| The `go` command can use its bundled Go toolchain as well as other versions |
| that it finds in the local `PATH` or downloads as needed. |
| |
| The choice of Go toolchain being used depends on the `GOTOOLCHAIN` environment setting |
| and the `go` and `toolchain` lines in the main module's `go.mod` file or the current workspace's `go.work` file. |
| As you move between different main modules and workspaces, |
| the toolchain version being used can vary, just as module dependency versions do. |
| |
| In the standard configuration, the `go` command uses its own bundled toolchain |
| when that toolchain is at least as new as the `go` or `toolchain` lines in the main module or workspace. |
| For example, when using the `go` command bundled with Go 1.21.3 in a main module that says `go 1.21.0`, |
| the `go` command uses Go 1.21.3. |
| When the `go` or `toolchain` line is newer than the bundled toolchain, |
| the `go` command runs the newer toolchain instead. |
| For example, when using the `go` command bundled with Go 1.21.3 in a main module that says `go 1.21.9`, |
| the `go` command finds and runs Go 1.21.9 instead. |
| It first looks in the PATH for a program named `go1.21.9` and otherwise downloads and caches |
| a copy of the Go 1.21.9 toolchain. |
| This automatic toolchain switching can be disabled, but in that case, |
| for more precise forwards compatibility, |
| the `go` command will refuse to run in a main module or workspace in which the `go` line |
| requires a newer version of Go. |
| That is, the `go` line sets the minimum required Go version necessary to use a module or workspace. |
| |
| Modules that are dependencies of other modules may need to set a minimum Go version requirement |
| lower than the preferred toolchain to use when working in that module directly. |
| In this case, the `toolchain` line in `go.mod` or `go.work` sets a preferred toolchain |
| that takes precedence over the `go` line when the `go` command is deciding |
| which toolchain to use. |
| |
| The `go` and `toolchain` lines can be thought of as specifying the version requirements |
| for the module's dependency on the Go toolchain itself, just as the `require` lines in `go.mod` |
| specify the version requirements for dependencies on other modules. |
| The `go get` command manages the Go toolchain dependency just as it |
| manages dependencies on other modules. |
| For example, `go get go@latest` updates the module to require the latest released Go toolchain. |
| |
| The `GOTOOLCHAIN` environment setting can force a specific Go version, overriding |
| the `go` and `toolchain` lines. For example, to test a package with Go 1.21rc3: |
| |
| GOTOOLCHAIN=go1.21rc3 go test |
| |
| The default `GOTOOLCHAIN` setting is `auto`, which enables the toolchain switching described earlier. |
| The alternate form `<name>+auto` sets the default toolchain to use before deciding whether to |
| switch further. For example `GOTOOLCHAIN=go1.21.3+auto` directs the `go` command to |
| begin its decision with a default of using Go 1.21.3 but still use a newer toolchain if |
| directed by `go` and `toolchain` lines. |
| Because the default `GOTOOLCHAIN` setting can be changed with `go env -w`, |
| if you have Go 1.21.0 or later installed, then |
| |
| go env -w GOTOOLCHAIN=go1.21.3+auto |
| |
| is equivalent to replacing your Go 1.21.0 installation with Go 1.21.3. |
| |
| The rest of this document explains how Go toolchains are versioned, chosen, and managed in more detail. |
| |
| ## Go versions {#version} |
| |
| Released versions of Go use the version syntax ‘1.*N*.*P*’, denoting the *P*th release of Go 1.*N*. |
| The initial release is 1.*N*.0, like in ‘1.21.0’. Later releases like 1.*N*.9 are often referred to as patch releases. |
| |
| Go 1.*N* release candidates, which are issued before 1.*N*.0, use the version syntax ‘1.*N*rc*R*’. |
| The first release candidate for Go 1.*N* has version 1.*N*rc1, like in `1.23rc1`. |
| |
| The syntax ‘1.*N*’ is called a “language version”. It denotes the overall family of Go releases |
| implementing that version of the Go language and standard library. |
| |
| The language version for a Go version is the result of truncating everything after the *N*: |
| 1.21, 1.21rc2, and 1.21.3 all implement language version 1.21. |
| |
| Released Go toolchains such as Go 1.21.0 and Go 1.21rc1 report that specific version |
| (for example, `go1.21.0` or `go1.21rc1`) |
| from `go version` and [`runtime.Version`](/pkg/runtime/#Version). |
| Unreleased (still in development) Go toolchains built from the Go development repository |
| instead report only the language version (for example, `go1.21`). |
| |
| Any two Go versions can be compared to decide whether one is less than, greater than, |
| or equal to the other. If the language versions are different, that decides the comparison: |
| 1.21.9 < 1.22. Within a language version, the ordering from least to greatest is: |
| the language version itself, then release candidates ordered by *R*, then releases ordered by *P*. |
| |
| For example, 1.21 < 1.21rc1 < 1.21rc2 < 1.21.0 < 1.21.1 < 1.21.2. |
| |
| Before Go 1.21, the initial release of a Go toolchain was version 1.*N*, not 1.*N*.0, |
| so for *N* < 21, the ordering is adjusted to place 1.*N* after the release candidates. |
| |
| For example, 1.20rc1 < 1.20rc2 < 1.20rc3 < 1.20 < 1.20.1. |
| |
| Earlier versions of Go had beta releases, with versions like 1.18beta2. |
| Beta releases are placed immediately before release candidates in the version ordering. |
| |
| For example, 1.18beta1 < 1.18beta2 < 1.18rc1 < 1.18 < 1.18.1. |
| |
| <!-- Unpublished note: the download page also lists Go 1.9.2rc2, which does not respect |
| this version syntax. That was created as a test of some potential release automation |
| before Go 1.9.2 but is not considered a “real” toolchain. --> |
| |
| ## Go toolchain names {#name} |
| |
| The standard Go toolchains are named <code>go<i>V</i></code> where *V* is a Go version |
| denoting a beta release, release candidate, or release. |
| For example, `go1.21rc1` and `go1.21.0` are toolchain names; |
| `go1.21` and `go1.22` are not (the initial releases are `go1.21.0` and `go1.22.0`), |
| but `go1.20` and `go1.19` are. |
| |
| Non-standard toolchains use names of the form <code>go<i>V</i>-<i>suffix</i></code> |
| for any suffix. |
| |
| Toolchains are compared by comparing the version <code><i>V</i></code> embedded in the name |
| (dropping the initial `go` and discarding off any suffix beginning with `-`). |
| For example, `go1.21.0` and `go1.21.0-custom` compare equal for ordering purposes. |
| |
| ## Module and workspace configuration {#config} |
| |
| Go modules and workspaces specify version-related configuration |
| in their `go.mod` or `go.work` files. |
| |
| The `go` line declares the minimum required Go version for using |
| the module or workspace. |
| For compatibility reasons, if the `go` line is omitted from a `go.mod` file, |
| the module is considered to have an implicit `go 1.16` line, |
| and if the `go` line is omitted from a `go.work` file, |
| the workspace is considered to have an implicit `go 1.18` line. |
| |
| The `toolchain` line declares a suggested toolchain to use with |
| the module or workspace. |
| As described in “[Go toolchain selection](#select)” below, |
| the `go` command may run this specific toolchain when operating |
| in that module or workspace |
| if the default toolchain's version is less than the suggested toolchain's version. |
| If the `toolchain` line is omitted, |
| the module or workspace is considered to have an implicit |
| <code>toolchain go<i>V</i></code> line, |
| where *V* is the Go version from the `go` line. |
| |
| For example, a `go.mod` that says `go 1.21.0` with no `toolchain` line |
| is interpreted as if it had a `toolchain go1.21.0` line. |
| |
| The Go toolchain refuses to load a module or workspace that declares |
| a minimum required Go version greater than the toolchain's own version. |
| |
| For example, Go 1.21.2 will refuse to load a module or workspace |
| with a `go 1.21.3` or `go 1.22` line. |
| |
| A module's `go` line must declare a version greater than or equal to |
| the `go` version declared by each of the modules listed in `require` statements. |
| A workspace's `go` line must declare a version greater than or equal to |
| the `go` version declared by each of the modules listed in `use` statements. |
| |
| For example, if module *M* requires a dependency *D* with a `go.mod` |
| that declares `go 1.22.0`, then *M*'s `go.mod` cannot say `go 1.21.3`. |
| |
| The `go` line for each module sets the language version the compiler |
| enforces when compiling packages in that module. |
| The language version can be changed on a per-file basis by using a |
| [build constraint](/cmd/go#hdr-Build_constraints): |
| if a build constraint is present and implies a minimum version of at least `go1.21`, |
| the language version used when compiling that file will be that minimum version. |
| |
| For example, a module containing code that uses the Go 1.21 language version |
| should have a `go.mod` file with a `go` line such as `go 1.21` or `go 1.21.3`. |
| If a specific source file should be compiled only when using a newer Go toolchain, |
| adding `//go:build go1.22` to that source file both ensures that only Go 1.22 and |
| newer toolchains will compile the file and also changes the language version in that |
| file to Go 1.22. |
| |
| The `go` and `toolchain` lines are most conveniently and safely modified |
| by using `go get`; see the [section dedicated to `go get` below](#get). |
| |
| Before Go 1.21, Go toolchains treated the `go` line as an advisory requirement: |
| if builds succeeded the toolchain assumed everything worked, |
| and if not it printed a note about the potential version mismatch. |
| Go 1.21 changed the `go` line to be a mandatory requirement instead. |
| This behavior is partly backported to earlier language versions: |
| Go 1.19 releases starting at Go 1.19.13 and Go 1.20 releases starting at Go 1.20.8, |
| refuse to load workspaces or modules declaring version Go 1.22 or later. |
| |
| Before Go 1.21, toolchains did not require a module |
| or workspace to have a `go` line greater than or equal to the |
| `go` version required by each of its dependency modules. |
| |
| ## The `GOTOOLCHAIN` setting {#GOTOOLCHAIN} |
| |
| The `go` command selects the Go toolchain to use based on the `GOTOOLCHAIN` setting. |
| To find the `GOTOOLCHAIN` setting, the `go` command uses the standard rules for any |
| Go environment setting: |
| |
| - If `GOTOOLCHAIN` is set to a non-empty value in the process environment |
| (as queried by [`os.Getenv`](/pkg/os/#Getenv)), the `go` command uses that value. |
| |
| - Otherwise, if `GOTOOLCHAIN` is set in the user's environment default file |
| (managed with |
| [`go env -w` and `go env -u`](/cmd/go/#hdr-Print_Go_environment_information)), |
| the `go` command uses that value. |
| |
| - Otherwise, if `GOTOOLCHAIN` is set in the bundled Go toolchain's environment |
| default file (`$GOROOT/go.env`), the `go` command uses that value. |
| |
| In standard Go toolchains, the `$GOROOT/go.env` file sets the default `GOTOOLCHAIN=auto`, |
| but repackaged Go toolchains may change this value. |
| |
| If the `$GOROOT/go.env` file is missing or does not set a default, the `go` command |
| assumes `GOTOOLCHAIN=local`. |
| |
| Running `go env GOTOOLCHAIN` prints the `GOTOOLCHAIN` setting. |
| |
| ## Go toolchain selection {#select} |
| |
| At startup, the `go` command selects which Go toolchain to use. |
| It consults the `GOTOOLCHAIN` setting, |
| which takes the form `<name>`, `<name>+auto`, or `<name>+path`. |
| `GOTOOLCHAIN=auto` is shorthand for `GOTOOLCHAIN=local+auto`; |
| similarly, `GOTOOLCHAIN=path` is shorthand for `GOTOOLCHAIN=local+path`. |
| The `<name>` sets the default Go toolchain: |
| `local` indicates the bundled Go toolchain |
| (the one that shipped with the `go` command being run), and otherwise `<name>` must |
| be a specific Go toolchain name, such as `go1.21.0`. |
| The `go` command prefers to run the default Go toolchain. |
| As noted above, starting in Go 1.21, Go toolchains refuse to run in |
| workspaces or modules that require newer Go versions. |
| Instead, they report an error and exit. |
| |
| When `GOTOOLCHAIN` is set to `local`, the `go` command always runs the bundled Go toolchain. |
| |
| When `GOTOOLCHAIN` is set to `<name>` (for example, `GOTOOLCHAIN=go1.21.0`), |
| the `go` command always runs that specific Go toolchain. |
| If a binary with that name is found in the system PATH, the `go` command uses it. |
| Otherwise the `go` command uses a Go toolchain it downloads and verifies. |
| |
| When `GOTOOLCHAIN` is set to `<name>+auto` or `<name>+path` (or the shorthands `auto` or `path`), |
| the `go` command selects and runs a newer Go version as needed. |
| Specifically, it consults the `toolchain` and `go` lines in the current workspace's |
| `go.work` file or, when there is no workspace, |
| the main module's `go.mod` file. |
| If the `go.work` or `go.mod` file has a `toolchain <tname>` line |
| and `<tname>` is newer than the default Go toolchain, |
| then the `go` command runs `<tname>` instead. |
| If the file has a `toolchain default` line, |
| then the `go` command runs the default Go toolchain, |
| disabling any attempt at updating beyond `<name>`. |
| Otherwise, if the file has a `go <version>` line |
| and `<version>` is newer than the default Go toolchain, |
| then the `go` command runs `go<version>` instead. |
| |
| To run a toolchain other than the bundled Go toolchain, |
| the `go` command searches the process's executable path |
| (`$PATH` on Unix and Plan 9, `%PATH%` on Windows) |
| for a program with the given name (for example, `go1.21.3`) and runs that program. |
| If no such program is found, the `go` command |
| [downloads and runs the specified Go toolchain](#download). |
| Using the `GOTOOLCHAIN` form `<name>+path` disables the download fallback, |
| causing the `go` command to stop after searching the executable path. |
| |
| Running `go version` prints the selected Go toolchain's version |
| (by running the selected toolchain's implementation of `go version`). |
| |
| Running `GOTOOLCHAIN=local go version` prints the bundled Go toolchain's version. |
| |
| Starting in Go 1.24, you can trace the `go` command's toolchain selection process |
| by adding `toolchaintrace=1` to the `GODEBUG` environment variable when you run the |
| `go` command. |
| |
| ## Go toolchain switches {#switch} |
| |
| For most commands, the workspace's `go.work` or the main module's `go.mod` |
| will have a `go` line that is at least as new as the `go` line in any module dependency, |
| due to the version ordering [configuration requirements](#config). |
| In this case, the startup toolchain selection runs a new enough Go toolchain |
| to complete the command. |
| |
| Some commands incorporate new module versions as part of their operation: |
| `go get` adds new module dependencies to the main module; |
| `go work use` adds new local modules to the workspace; |
| `go work sync` resynchronizes a workspace with local modules that may have been updated |
| since the workspace was created; |
| `go install package@version` and `go run package@version` |
| effectively run in an empty main module and add `package@version` as a new dependency. |
| All these commands may encounter a module with a `go.mod` `go` line |
| requiring a newer Go version than the currently executed Go version. |
| |
| When a command encounters a module requiring a newer Go version |
| and `GOTOOLCHAIN` permits running different toolchains |
| (it is one of the `auto` or `path` forms), |
| the `go` command chooses and switches to an appropriate newer toolchain |
| to continue executing the current command. |
| |
| Any time the `go` command switches toolchains after startup toolchain selection, |
| it prints a message explaining why. For example: |
| |
| go: module example.com/widget@v1.2.3 requires go >= 1.24rc1; switching to go 1.27.9 |
| |
| As shown in the example, the `go` command may switch to a toolchain |
| newer than the discovered requirement. |
| In general the `go` command aims to switch to a supported Go toolchain. |
| |
| To choose the toolchain, the `go` command first obtains a list of available toolchains. |
| For the `auto` form, the `go` command downloads a list of available toolchains. |
| For the `path` form, the `go` command scans the PATH for any executables |
| named for valid toolchains and uses a list of all the toolchains it finds. |
| Using that list of toolchains, the `go` command identifies up to three candidates: |
| |
| - the latest release candidate of an unreleased Go language version (1.*N*₃rc*R*₃), |
| - the latest patch release of the most recently released Go language version (1.*N*₂.*P*₂), and |
| - the latest patch release of the previous Go language version (1.*N*₁.*P*₁). |
| |
| These are the supported Go releases according to Go's [release policy](/doc/devel/release#policy). |
| Consistent with [minimal version selection](https://research.swtch.com/vgo-mvs), |
| the `go` command then conservatively uses the candidate with the _minimum_ (oldest) |
| version that satisfies the new requirement. |
| |
| For example, suppose `example.com/widget@v1.2.3` requires Go 1.24rc1 or later. |
| The `go` command obtains the list of available toolchains |
| and finds that the latest patch releases of the two most recent Go toolchains are |
| Go 1.28.3 and Go 1.27.9, |
| and the release candidate Go 1.29rc2 is also available. |
| In this situation, the `go` command will choose Go 1.27.9. |
| If `widget` had required Go 1.28 or later, the `go` command would choose Go 1.28.3, |
| because Go 1.27.9 is too old. |
| If `widget` had required Go 1.29 or later, the `go` command would choose Go 1.29rc2, |
| because both Go 1.27.9 and Go 1.28.3 are too old. |
| |
| Commands that incorporate new module versions that require new Go versions |
| write the new minimum `go` version requirement to the current workspace's `go.work` file |
| or the main module's `go.mod` file, updating the `go` line. |
| For [repeatability](https://research.swtch.com/vgo-principles#repeatability), |
| any command that updates the `go` line also updates the `toolchain` line |
| to record its own toolchain name. |
| The next time the `go` command runs in that workspace or module, |
| it will use that updated `toolchain` line during [toolchain selection](#select). |
| |
| For example, `go get example.com/widget@v1.2.3` may print a switching notice |
| like above and switch to Go 1.27.9. |
| Go 1.27.9 will complete the `go get` and update the `toolchain` line |
| to say `toolchain go1.27.9`. |
| The next `go` command run in that module or workspace will select `go1.27.9` |
| during startup and will not print any switching message. |
| |
| In general, if any `go` command is run twice, if the first prints a switching |
| message, the second will not, because the first also updated `go.work` or `go.mod` |
| to select the right toolchain at startup. |
| The exception is the `go install package@version` and `go run package@version` forms, |
| which run in no workspace or main module and cannot write a `toolchain` line. |
| They print a switching message every time they need to switch |
| to a newer toolchain. |
| |
| ## Downloading toolchains {#download} |
| |
| When using `GOTOOLCHAIN=auto` or `GOTOOLCHAIN=<name>+auto`, the Go command |
| downloads newer toolchains as needed. |
| These toolchains are packaged as special modules |
| with module path `golang.org/toolchain` |
| and version <code>v0.0.1-go<i>VERSION</i>.<i>GOOS</i>-<i>GOARCH</i></code>. |
| Toolchains are downloaded like any other module, |
| meaning that toolchain downloads can be proxied by setting `GOPROXY` |
| and have their checksums checked by the Go checksum database. |
| Because the specific toolchain used depends on the system's own |
| default toolchain as well as the local operating system and architecture (GOOS and GOARCH), |
| it is not practical to write toolchain module checksums to `go.sum`. |
| Instead, toolchain downloads fail for lack of verification if `GOSUMDB=off`. |
| `GOPRIVATE` and `GONOSUMDB` patterns do not apply to the toolchain downloads. |
| |
| ## Managing Go version module requirements with `go get` {#get} |
| |
| In general the `go` command treats the `go` and `toolchain` lines |
| as declaring versioned toolchain dependencies of the main module. |
| The `go get` command can manage these lines just as it manages |
| the `require` lines that specify versioned module dependencies. |
| |
| For example, `go get go@1.22.1 toolchain@1.24rc1` changes the main module's |
| `go.mod` file to read `go 1.22.1` and `toolchain go1.24rc1`. |
| |
| The `go` command understands that the `go` dependency requires a `toolchain` dependency |
| with a greater or equal Go version. |
| |
| Continuing the example, a later `go get go@1.25.0` will update |
| the toolchain to `go1.25.0` as well. |
| When the toolchain matches the `go` line exactly, it can be |
| omitted and implied, so this `go get` will delete the `toolchain` line. |
| |
| The same requirement applies in reverse when downgrading: |
| if the `go.mod` starts at `go 1.22.1` and `toolchain go1.24rc1`, |
| then `go get toolchain@go1.22.9` will update only the `toolchain` line, |
| but `go get toolchain@go1.21.3` will downgrade the `go` line to |
| `go 1.21.3` as well. |
| The effect will be to leave just `go 1.21.3` with no `toolchain` line. |
| |
| The special form `toolchain@none` means to remove any `toolchain` line, |
| as in `go get toolchain@none` or `go get go@1.25.0 toolchain@none`. |
| |
| The `go` command understands the version syntax for |
| `go` and `toolchain` dependencies as well as queries. |
| |
| For example, just as `go get example.com/widget@v1.2` uses |
| the latest `v1.2` version of `example.com/widget` (perhaps `v1.2.3`), |
| `go get go@1.22` uses the latest available release of the Go 1.22 language version |
| (perhaps `1.22rc3`, or perhaps `1.22.3`). |
| The same applies to `go get toolchain@go1.22`. |
| |
| The `go get` and `go mod tidy` commands maintain the `go` line to |
| be greater than or equal to the `go` line of any required dependency module. |
| |
| For example, if the main module has `go 1.22.1` and we run |
| `go get example.com/widget@v1.2.3` which declares `go 1.24rc1`, |
| then `go get` will update the main module's `go` line to `go 1.24rc1`. |
| |
| Continuing the example, a later `go get go@1.22.1` will |
| downgrade `example.com/widget` to a version compatible with Go 1.22.1 |
| or else remove the requirement entirely, |
| just as it would when downgrading any other dependency of `example.com/widget`. |
| |
| Before Go 1.21, the suggested way to update a module to a new Go version (say, Go 1.22) |
| was `go mod tidy -go=1.22`, to make sure that any adjustments |
| specific to Go 1.22 were made to the `go.mod` at the same time that the |
| `go` line is updated. |
| That form is still valid, but the simpler `go get go@1.22` is now preferred. |
| |
| When `go get` is run in a module in a directory contained in a workspace root, |
| `go get` mostly ignores the workspace, |
| but it does update the `go.work` file to upgrade the `go` line |
| when the workspace would otherwise be left with too old a `go` line. |
| |
| ## Managing Go version workspace requirements with `go work` {#work} |
| |
| As noted in the previous section, `go get` run in a directory |
| inside a workspace root will take care to update the `go.work` file's `go` line |
| as needed to be greater than or equal to any module inside that root. |
| However, workspaces can also refer to modules outside the root directory; |
| running `go get` in those directories may result in an invalid workspace |
| configuration, one in which the `go` version declared in `go.work` is less |
| than one or more of the modules in the `use` directives. |
| |
| The command `go work use`, which adds new `use` directives, also checks |
| that the `go` version in the `go.work` file is new enough for all the |
| existing `use` directives. |
| To update a workspace that has gotten its `go` version out of sync |
| with its modules, run `go work use` with no arguments. |
| |
| The commands `go work init` and `go work sync` also update the `go` |
| version as needed. |
| |
| To remove the `toolchain` line from a `go.work` file, use |
| `go work edit -toolchain=none`. |
| |