Go: A Documentary

About this report

This page reconstructs how the Go runtime and compiler toolchain evolved, from the first compiler and runtime commits in 2008 to the current development tree (Go 1.28, unreleased as of 2026-10-30). It is built only from the commit history: commit subjects, commit messages (which often carry the design rationale and benchmark tables), and diffs. Release notes were deliberately not used. Internal changes they skip are included and tagged internal; changes to user-facing API, behaviour or flags are tagged user-visible.

The page covers 28,950 in-scope commits: 19,100 before Go 1.18 and 9,850 from Go 1.18 on. The two periods were read separately, with the same method, and are joined at the 1.17 → 1.18 seam.

Method (map → reduce).

  1. Map. Every in-scope commit was tagged with topic areas by the files it touches. For example, mgc*.go goes to the GC, internal/runtime/maps to data structures, and ssa/_gen/ARM64.rules to backends. A commit can belong to more than one area. Historic paths were first mapped to their modern equivalents: src/pkg/runtime/*.c/.goc → runtime, src/cmd/gc → frontend, 5g/6g/8g/9g → backends, 5l/6l/8l, src/cmd/ld → linker, src/liblink → cmd/internal/obj. Files of the old monolithic gc package (esc.go, inl.go, walk.go, ssa.go, plive.go, reflect.go, …) were mapped by file name.
  2. Reduce. For each area, a reader went through every non-noise commit subject in the area, plus the full messages of the design-heavy commits and, in some areas, the diffs. It picked the commits that matter and clustered them into threads: coherent bodies of work such as the concurrent GC, contiguous stacks, the SSA backend, the new linker, the GC pacer, Swiss maps or PGO. Each thread gets:
    • its design;
    • a timeline listing, per release, what landed (Done) and what was still unfinished afterwards (Left open), based on TODOs, “for now”, “follow-up” and “disabled by default” notes in the messages, or on what the next stage had to fix;
    • its status: at HEAD for 1.18+ threads, at go1.17 for earlier ones.
    Noise filter (pre-1.18 only). Before the pre-1.18 readers started, a subject-line heuristic set aside 3,371 of the 19,100 commits as noise. These were tests-only changes, [release-branch] cherry-picks, and subjects matching patterns such as typo, comment, rename, clean up, skip, update, undo or revert. A later audit found 259 larger commits among them, each changing 30 or more lines, whose subjects matched only a weak pattern (for example “remove locks from netpoll hotpaths” or “replace func-based write barrier skipping”). A separate reader described those 259 and added them to the “Other notable changes” items. The remaining reverts, renames, clean-ups and test changes are not cited.
  3. Eras and seams. Before 1.18, the large areas were split into era slices at the big rewrites: the compiler’s C → Go translation (1.5), the SSA backend (1.7), the new linker (1.15–1.16), and the register ABI and types2 work (1.17). Where a thread continues across a slice boundary, or into the 1.18+ report, the thread carries Earlier history and Continues in links.
  4. Who read what. For 1.18+, the GC/allocator chapter and most of the compiler-optimization chapter were read by Claude Opus. The other 1.18+ areas, two gap passes, and all 16 pre-1.18 slices were read by Claude Sonnet. Each area in Part I opens with a short note giving its reader, how many of its commits it cites, and any caveats the reader reported. Every pre-1.18 slice cites all of its non-noise commits.
  5. Views. The Thread × release maps (one for 1.0–1.17, one for 1.18–1.28) show at a glance which releases moved which thread. Part I reads thread by thread, area by area, oldest era first. Part II regroups the same stages by release, adding changes that don’t belong to any thread. For pre-1.18 releases it also opens each area with a one-line digest. Part III (Paths not taken) covers the work that did not land: abandoned CL series, unmerged branches, declined or held proposals, and design docs that were never implemented. It explains why each one stopped, from the review record. Landed threads link to the Part III entries that relate to them.

How releases are delimited: Go 1.18 onwards. A “release” is a development cycle: the commits on master between the internal/goversion bump that opened the cycle and the bump that opened the next one, which happens when the previous release branch is cut. Freeze-period fixes count toward the cycle they landed in. Point-release backports (cherry-picks onto release-branch.go1.N) are not covered. Work developed on feature branches (dev.typeparams, dev.unified, dev.simd, …) counts toward the cycle where it merged to master, so author dates can be older than the cycle.

Release Commit range on master Cycle opened In-scope commits
Go 1.18 46fd547d89..936c7fbc1c 2021-08-12 1,569
Go 1.19 936c7fbc1c..d723df76da 2022-02-28 735
Go 1.20 d723df76da..83f8688915 2022-08-02 953
Go 1.21 83f8688915..21ff9be0eb 2023-01-17 967
Go 1.22 21ff9be0eb..1653833811 2023-07-18 883
Go 1.23 1653833811..c622f5c341 2024-01-19 667
Go 1.24 c622f5c341..9da530f11a 2024-07-22 718
Go 1.25 9da530f11a..2696a11a97 2025-02-03 650
Go 1.26 2696a11a97..83c44ec032 2025-07-23 1,082
Go 1.27 83c44ec032..6c87434d24 2026-01-21 861
Go 1.28 (dev) 6c87434d24..4494c64f5a (HEAD) 2026-07-14 766

How releases are delimited: Go 1.0 – 1.17. Before Go 1.13 there was no internal/goversion bump to cut cycles on, and early release branches were often merged back into master. So for these releases a commit belongs to the first release tag that contains it: git rev-list go1.N ^go1.(N-1). The 54 cherry-picks made on release branches ([release-branch.go1.N] subjects) are treated as noise. “Go 1.0” means everything up to the go1 tag: the whole pre-release history, from the first compiler and runtime commits in June 2008, through the open-sourcing in November 2009 and the weekly snapshots, to Go 1. Joke commits dated 1972–1988 at the root of the repository are excluded. The two conventions meet without a gap: every in-scope commit reachable from the 1.18 cycle’s opening commit is contained in the go1.17 tag.

Release Commits Tagged In-scope commits
Go 1.0 go1 (2008-06 → 2012-03) 2012-03-28 3,138
Go 1.1 go1.1 ^go1 2013-05-13 967
Go 1.2 go1.2 ^go1.1 2013-11-29 531
Go 1.3 go1.3 ^go1.2 2014-06-19 599
Go 1.4 go1.4 ^go1.3 2014-12-11 644
Go 1.5 go1.5 ^go1.4 2015-08-19 1,617
Go 1.6 go1.6 ^go1.5 2016-02-17 719
Go 1.7 go1.7 ^go1.6 2016-08-15 1,594
Go 1.8 go1.8 ^go1.7 2017-02-16 1,012
Go 1.9 go1.9 ^go1.8 2017-08-24 1,136
Go 1.10 go1.10 ^go1.9 2018-02-15 793
Go 1.11 go1.11 ^go1.10 2018-08-24 991
Go 1.12 go1.12 ^go1.11 2019-02-25 659
Go 1.13 go1.13 ^go1.12 2019-09-03 567
Go 1.14 go1.14 ^go1.13 2020-02-25 826
Go 1.15 go1.15 ^go1.14 2020-08-11 963
Go 1.16 go1.16 ^go1.15 2021-02-16 862
Go 1.17 go1.17 ^go1.16 2021-08-16 1,482

Paths in scope:

Out of scope: cmd/go, cmd/cgo, cmd/dist, go/types (except as the mirror of types2), and the rest of the standard library.

Reading the citations. Every claim cites the commits it rests on, and each hash links to go.googlesource.com. A bullet often condenses dozens of commits. Benchmark figures are quoted from the commit messages and reflect the author’s measurement at the time. A small superscript after a hash (for example 1.9) marks a commit that landed in a different release from the bullet that cites it, usually as context. About 160 of the roughly 23,000 pre-1.18 citations carry one, most of them off by a single release.

Design docs and discussions. Threads with a traceable design document or discussion show them in a box above their design section, and the Design docs and discussions page lists them all: 556 links on 226 threads. They come from three sources. The first is each thread’s own commits, through the issues those commits reference and the design docs (golang/proposal, Google Docs, go.dev/s short links), proposals, and golang-dev, golang-nuts and GitHub discussion threads those issues link to. The second is the curated links of Go: A Documentary. The third is the golang/proposal repository. A Claude Sonnet reader picked the relevant ones per thread from that pool by title, and each link says where it was found. These are pointers only: the thread text itself was written from the commits alone.

Contents

Part I — Topics

Thread by thread, oldest era first.

Part II — Releases

Release by release, every area.

Part III — Paths not taken

Work that was built or designed but did not land: 39 efforts, by topic.

Thread × release map · Experiments and knobs

Overview

This section summarizes the 436 threads in Part I: 268 for Go 1.0–1.17 and 168 for Go 1.18 onwards. It covers two things: the big arcs that cut across the runtime and the compiler, and what defines each release. Each link jumps to the full thread, which has the design and the commit-by-commit timeline.

The big arcs

Each arc is a chain of the stages it went through. “→” separates releases, and HEAD means the development tree as of 2026-10-30. Arcs that began before 1.18 open with a Before 1.18 line.

The toolchain rewrites itself (before 1.18).

Generics, end to end.

GC: pacing, then the heap layout, then the marking algorithm.

Allocation fast path. mallocgc split into specialized paths (1.24) → generated size-specialized malloc (on in master during 1.26 but off in go1.26.0 → on in 1.27 → flag removed in 1.28). Alongside it:

Memory-management APIs. unique (1.23) → public weak and AddCleanup (1.24) → checkfinalizer and parallel cleanup goroutines (1.25). Also Pinner (1.21) and heap-base randomization (1.26).

Concurrency runtime.

Maps and hashing.

Observability.

Stacks and panics.

Compiler middle end.

Backends.

Linker.

What defines each release

The links go to the release in Part II.