• Most information was taken from the release notes.
  • Release is schedules for February 2023. Releases happened between 16th and 25th in the past, so I assume that 1.20 will be released end of February as well. Final release was on 1st of February 2023, a little bit earlier than usual for an even version number Go release.
  • I talked about this in our #34 Leipzig Gophers Meetup.


Package context received WithCancelCause which allows to cancel a context with a given error. This is pretty nice to have something more meaningful than the usual context.Canceled error, that won't tell you anything about why something got canceled. (playground)


Support for wrapping multiple errors: - errors.Join to wrap multiple errors into one (error messages will be newline delimited) - fmt.Errorf now also supports multiple %w format verbs - (playground)

HTTP Response Controller

http.ResponseController wraps an http.ResponseWriter and makes it more convenient to configure it in a Handler, e.g. no need to make checked-cast to an http.Hijacker anymore, just call responseController.Hijack(). You can also easily overwrite read and write deadlines using the response controller.

Language Changes

Slice to array conversions are now a bit easier to write (playground).

	x := []int{1, 2, 3, 4}
	var y [4]int
	// Go 1.17+
	// y = *(*[4]int)(x)
	y = [4]int(x)

Note that this will

  • copy the elements from the slice to the array
  • conversion from array to slice works the same way
  • array to slice conversion will run-time panic if the target slice won't fit the array (len(slice) < len(array))

Three new functions for unsafe modification fo slices, SliceData, String, StringData. Don't use it, except you know what you're doing.

The language specification now defines that

  • struct values are compared one field at a time, in the order fields were declared in the struct definition
  • array values are compared one element at a time, in increasing index order
    • Note that slices still cannot be checked for equality using the == operator!
  • comparisons stop at the first mismatch This will have no effect on existing programs, just a clear description in the spec what was already implemented

The comparable constraint is now satisfied by comparable types, sound obvious, right 😅? In practice this means that a comparable constrained type parameter can be instantiated with non-strictly comparable types, like interfaces. As an example, you can do the following from Go 1.20 (playground):

func f[K comparable, V any](keys []K, values []V) map[K]V {
	m := make(map[K]V, len(keys))
	for idx, key := range keys {
		m[key] = values[idx]
	return m


  • Go distribution will become a bit smaller because pre-compiled packages from the standard library are removed. Instead, packages of the standard library will be compiled on the fly and then stored in the build cache (like any other package).
  • go test -json will emit a start Action at the beginning of each test execution.
  • The go command received a -C flag, to change working directory.
  • Build related commands, go build and go install, received a -cover flag to build with code coverage instrumentation. There will be a separate talk today, that is going to cover this topic in detail.
  • net and os/user packages are now pure Go packages under macOS, i.e. they don't require cgo anymore.
  • cgo is not required anymore for the race-detector under macOS (you can run those tests now without having XCode installed)


  • Experimental support for arena allocations (language proposal). Allocations from the memory arena are not considered by the GC and the arena will be freed manually all at once. (package docs). Should be handled with care due to easy to introduce use-after-free bugs.
  • Up to 2% less CPU usage, due to GC improvements.


  • Support for PGO, profile guided optimization, in builds. This means that the compiler can leverage run-time profile data to optimize the compiled code, e.g. by more aggressive inlining. Claimed performane improvement are about 3-4%. More PGO optimizations will be added in further releases.
    • Record a CPU profile and pass that to the compiler.
  • Up to 10% faster build speeds, which brings compile times down to pre-generic levels.
  • There's a Go blog post with more details: https://go.dev/blog/pgo-preview

Standard Library

  • New crypto/ecdh and crypto/ecdsa packages which replaces the more low-level crypto/elliptic. Fillipo Valsorda wrote a deep-dive on the Go 1.20 crypto changes, e.g. the elliptic curve crypto packages don't rely on math/big anymore, which makes them constant time.
  • ReverseProxy Rewrite hook superceeds httputil.Director and now receives in- and outbound requests with its *httputil.ProxyRequest argument (unlike a Director function which just received an outbound request).

Minor standard library changes

  • archive/tar and archive/zip return ErrInsecurePath if an entry has an absolute path, contains invalid characters etc. Note that this is currently behind a feature flag, GODEBUG=zipinsecurepath=0 but might get the default in a future release.
  • the bytes package received
    • Clone, which basically returns a clone of the given byte slice. This is a useful utitlity with a pretty minimal implementation.
    • TrimPrefix and TrimSuffix got siblings, called CutPrefix and CutSuffix. The difference is that the Cut functions will return if something was removed or not.
  • crypto/tls TLS certificates are now shared across all clients using a certificate, which might lead to significantly less memory usage. If a handshake fails a new CertificateVerificationError is returned.
  • io.OffsetWriter basically wraps an io.WriterAt and adds a given fixed offset to each Seek, Write etc. call.
  • Directory trees are usually traversed using fs.Walk. There's a new SkipAll error that can be used to immediately stop the recursion of fs.Walk, but this error will be consumed and the call will end successfully. This is mostly for convenience, since you could have achieved the same before, just that the caller had to filter out the custom error that indicates the traversal stop.
  • math/rand will automatically seed the global RNG, this can deactivated with GODEBUG=randautoseed=0. I'd argue against using the global RNG and to always instantiate a local instance. The same applies to any other global instance.
  • We got three new time formats:
    • DateTime = "2006-01-02 15:04:05"
    • DateOnly = "2006-01-02"
    • TimeOnly = "15:04:05"
  • testing.B can now report the elapsed time


  • There's a proposal to add structured logging support to the standard library with package log/slog
  • Can be used already by importing golang.org/x/exp/slog
  • Currently
    • we only have package log, a simple logger that has no support for levels etc.
    • every logging library needs to define their own Logger interface
  • At a high level slog is build from three parts:
    • Logger is user-facing part of the API, exposing methods like .Info() or .Error().

      A Logger records structured information about each call to its Log, Debug, Info, Warn, and Error methods. For each call, it creates a Record and passes it to a Handler.

    • Record contains data of a logging even.

      A Record holds information about a log event. Copies of a Record share state. Do not modify a Record after handing out a copy to it.

    • Handler is a logging backend implementation, that handles records emitted from a Logger.

      A Handler handles log records produced by a Logger. A typical handler may print log records to standard error, or write them to a file or database, or perhaps augment them with additional attributes and pass them on to another handler.

  • playground, copied from this article: https://mrkaran.dev/posts/structured-logging-in-go-with-slog/