New in Go 1.21: Toolchains

Elton Minetto - Oct 21 '23 - - Dev Community

The version 1.21 of the language implemented an essential new feature. According to the documentation:

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.

I did a proof of concept to validate how this new functionality works, which I will describe in this post.

On my machine, I had the following version of go:



go version
go version go1.21.0 darwin/arm64


Enter fullscreen mode Exit fullscreen mode

I created three libs, each with a different version of go as a requirement. In the commands below, you can see the content of each go.mod of the libs:

cd l1 ; cat go.mod; cd ..
module github.com/eminetto/l1

go 1.19.0

❯ cd l2; cat go.mod; cd ..
module github.com/eminetto/l2

go 1.20.0

❯ cd l3; cat go.mod; cd ..
module github.com/eminetto/l3

go 1.21.1


Enter fullscreen mode Exit fullscreen mode

Starting with version 1.21, the go 1.20.0 line of the go.mod file, in this example of the l2 lib, indicates the minimum language version required we need to use to compile it.

Next, I created a project to import the three libraries. The following diagram shows the dependencies:

toolchain

The main.go of the proj contains:



package main

import (
    "fmt"

    "github.com/eminetto/l1"
    "github.com/eminetto/l2"
    "github.com/eminetto/l3"
)

func main() {
    fmt.Println(l1.Sum(1, 2))
    fmt.Println(l2.Sum(1, 2))
    fmt.Println(l3.Sum(1, 2))
}


Enter fullscreen mode Exit fullscreen mode

The project's go.mod contains:



module github.com/eminetto/proj

go 1.21.0

require (
    github.com/eminetto/l1 v0.0.0-20231012141607-826d3914801f
    github.com/eminetto/l2 v0.0.0-20231012141624-28120aab8596
    github.com/eminetto/l3 v0.0.0-20231012141624-2810bakab896
)


Enter fullscreen mode Exit fullscreen mode

I ran the project, and it worked without errors:



❯ go run main.go
3
3
3


Enter fullscreen mode Exit fullscreen mode

Next, I simulated the process of updating one of the libs.
To do this, I updated the l3 lib to a newer version of Go:

cd l3; cat go.mod
module github.com/eminetto/l3

go 1.21.3


Enter fullscreen mode Exit fullscreen mode

I pushed it to the repository and created a new version (v0.0.1).

According to the documentation:

The Go toolchain refuses to load a module or workspace that declares a minimum required Go version greater than the toolchain’s own version.

To validate this, in the project, I updated the version of l3:



❯ go get github.com/eminetto/l3@v0.0.1
go: downloading github.com/eminetto/l3 v0.0.1
go: github.com/eminetto/l3@v0.0.1 requires go >= 1.21.3; switching to go1.21.3
go: upgraded go 1.21.0 => 1.21.3
go: upgraded github.com/eminetto/l3 v0.0.0-20231012141629-a747d5b44b93 => v0.0.1


Enter fullscreen mode Exit fullscreen mode

What's new is the following excerpt:



go: github.com/eminetto/l3@v0.0.1 requires go >= 1.21.3; switching to go1.21.3
go: upgraded go 1.21.0 => 1.21.3



Enter fullscreen mode Exit fullscreen mode

What happened was that the go command updated the version of Go installed on my machine to 1.21.3:



 go version
go version go1.21.3 darwin/arm64


Enter fullscreen mode Exit fullscreen mode

And the project's go.mod has also been updated to version 1.21.3.

cat go.mod 
module github.com/eminetto/proj

go 1.21.3

require (
        github.com/eminetto/l1 v0.0.0-20231012141607-826d3914801f
        github.com/eminetto/l2 v0.0.0-20231012141624-28120aab8596
        github.com/eminetto/l3 v0.0.1
)


Enter fullscreen mode Exit fullscreen mode

And the project continues to run without errors. My machine now has the minimum version necessary to import ALL libs and run without errors. In this case, it was updated to 1.21.3 because it was necessary to run l3 since the others are below the current version I had installed on my machine (1.21.0).

Another fact I noticed is that there is now one version of Go for the project and another for the rest of the operating system:

cd proj

Developer/post-toolchain/proj
❯ go version
go version go1.21.3 darwin/arm64

Developer/post-toolchain/proj
❯ cd ..

~/Developer/post-toolchain
❯ go version
go version go1.21.0 darwin/arm64


Enter fullscreen mode Exit fullscreen mode

The go command identifies that the proj directory requires a specific language version. And all this management is done automatically.

Let's now think about a slightly more complex example. Let's suppose that one of the libs, for example, l2, was updated to:



module github.com/eminetto/l2

go 1.24rc1


Enter fullscreen mode Exit fullscreen mode

The go command gets the list of available toolchains and finds that the most recent releases are Go 1.28.3, Go 1.27.9, and Go 1.29rc2. The go command will choose Go 1.27.9 in this situation.

If l2 required Go 1.28 or later, the go command would choose Go 1.28.3 because Go 1.27.9 is too old. If l2 required Go 1.29 or later, Go 1.29rc2 would be chosen because the other options are too old.

When executing the command go get github.com/eminetto/l2@v0.0.1 (the newest version of the package), it will update the project's go.mod file, and a new line will be added with the chosen toolchain:



 cat go.mod 
module github.com/eminetto/proj

go 1.27.9

toolchain go1.27.9

require (
        github.com/eminetto/l1 v0.0.0-20231012141607-826d3914801f
        github.com/eminetto/l2 v0.0.1
        github.com/eminetto/l3 v0.0.1
)



Enter fullscreen mode Exit fullscreen mode

You can find more details about the motivations behind this feature, the version naming, and advanced behavior settings in the language's official documentation.

This feature is another example of the language team's care to maintain compatibility between past and future versions. With this functionality, it will be possible to guarantee the longevity of applications written in Go, which is very important for the future of the language in increasingly complex environments.

Thanks to friends Matheus Mina, Tiago Temporin, and Eduardo Hitek for reviewing the text and suggesting improvements.

Originally published at https://eltonminetto.dev on October 18, 2023

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .