What is new in Go 1.15?
A field note on Go 1.15, with editorial components for code, references, tabs, steps, and callouts.
Table of Contents
Go 1.15 was released on August 11, 2020. It is not the kind of release that asks for a celebratory rewrite of every service; it is quieter than that. The value sits in compilation, runtime cost, and smaller details that make production Go feel more boring in the best sense.1Note 1Primary release note for Go 1.15.
Release field note
Go 1.15 as a maintenance release.
The interesting parts are not loud. Faster linking, cheaper defers, smaller binaries, and a few standard-library additions make the upgrade feel like housekeeping that pays rent.
Toolchain improvements.
Linker rewrite.
The most significant change in Go 1.15 is the rewritten linker. The release notes describe faster linking, lower memory use, and a Go implementation that gives future toolchain work a cleaner base.2Note 2Announcement context from the Go team.
A toolchain improvement is successful when the application code does not have to perform for it.
Measure the build you already have
Run the same package set before and after the upgrade. Keep the command boring so the result says something about the toolchain, not about a newly invented benchmark.
Watch memory while linking
Large services and generated codebases benefit most from the linker rewrite. Compare peak memory and wall time, not just final binary size.
Ship behind your normal checks
Go 1.15 is conservative, but toolchain upgrades still deserve CI, integration tests, and a small rollout window.
The migration note I would keep in a repository is short. It records the compiler version, a baseline build time, and the one or two project-level checks that should catch drift.
go version
go test ./...
go test -race ./...
go build -trimpath ./cmd/serviceSmaller binaries.
Go 1.15 also improves dead code elimination. Typical binaries are smaller, symbol tables are handled more efficiently, and deployment artifacts get a little easier to move around.
go test ./...
go build -trimpath ./cmd/service
go versionrepeatable local check
steps:
- run: go test ./...
- run: go build -trimpath ./cmd/serviceminimal ci step
Keep one short upgrade note beside the release branch. Mention compiler version, binary size, and any test-only changes that were required.
A small upgrade checklist
Upgrade note without shape
"We upgraded Go. The build is faster. CI is green." This is true, but it is hard to audit six months later.
Upgrade note with shape
"Go 1.14.7 to Go 1.15.15. Link time: 42s to 28s. Binary: 81MB to 76MB. No code changes." This is boring, which is useful.
- Link time
- The number most teams will feel first when working on large services or generated code.
- Memory pressure
- The number most likely to matter on CI workers with narrow resource limits.
- Artifact size
- The quieter win that compounds in container registries, deploy caches, and cold starts.
Runtime performance.
Defer performance.
The defer statement got a practical speedup. In many common cases, Go can use open-coded defers, making cleanup-heavy code less expensive while preserving the shape that humans actually want to read.
func processFile(filename string) error {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
return process(f)
}Zhaphar field note
The practical rule is simple:
- 01Keep
deferwhere it communicates ownership. - 02Measure hot paths before hand-optimizing.
- 03Prefer readable cleanup until a profile proves otherwise.
func BenchmarkDeferClose(b *testing.B) {
for i := 0; i < b.N; i++ {
closer := noopCloser{}
defer closer.Close()
}
}a tiny defer benchmark skeleton
Standard library updates.
Embedded timezone data.
The new time/tzdata package allows a program to embed timezone data directly in the binary. That matters for small containers, restricted systems, and deployments where the host filesystem cannot be trusted to provide the same zoneinfo files everywhere.3Note 3Useful when a deployed system does not provide zoneinfo files.
package main
import (
"fmt"
"time"
_ "time/tzdata"
)
func main() {
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
panic(err)
}
fmt.Println(time.Now().In(loc).Format(time.RFC3339))
}Test temporary directories.
testing.TB.TempDir gives tests a managed temporary directory that is automatically removed when the test finishes. It is a small API, but it removes a surprising amount of cleanup ceremony.
func TestSomething(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "sample.txt")
if err := os.WriteFile(path, []byte("hello"), 0o644); err != nil {
t.Fatal(err)
}
}Use Ctrl + K or / to search for follow-up notes across the site.
- Use
t.TempDir()for filesystem tests. - Keep cleanup local to the test instead of sharing global temporary paths.
- Only test the operating system behavior you actually depend on.
Compatibility notes.
Go 1.15 is intentionally conservative, but conservative does not mean invisible. When I review an upgrade like this, I put the risk in three buckets.
| Bucket | What to inspect | Typical signal |
|---|---|---|
| Toolchain | build, link, vet, race | CI duration and peak memory |
| Runtime | defers, allocation-heavy paths | profile deltas |
| Environment | timezone files, containers, tests | failures that only appear outside a laptop |
Not necessarily. A quiet release still deserves the same rollout discipline as any other runtime change. Upgrade a representative service first, then move the rest when the behavior is boring.
Build and link performance. It is visible in CI, easy to compare, and does not require a product narrative.
Watch error rates, memory, CPU, startup time, and any tests that depend on filesystem layout or timezones. Most projects will not see drama, but the habit is valuable.
Measure link and test time.
Watch runtime behavior.
Record the rollout notes.
Editorial component sync.
— I
Structured component sampler.
The blocks below are intentionally dense. They are here so the article can exercise the full reading system on one page: component headings, badges, prompt boxes, lists, tables, references, copy buttons, and interactive panels.
Stable New block Optional Beta Deprecated#A short component heading.
They let long technical essays carry reference material, comparisons, prompts, and supporting figures without turning into a separate documentation system.
The class names and component shapes stay aligned, but the colors, spacing, and placeholder media are adapted to the current Zhaphar design tokens.
- Code
- Use fenced Markdown for highlighted code, or CodeBlock when a caption is needed.
- References
- Use frontmatter references with inline Footnote markers and a closing References block.
- Lists
- Plain Markdown lists now render with the v3 list vocabulary.
package main
import "fmt"
func main() {
fmt.Println("Go 1.15 still rewards simple programs.")
}go tab panel
- go 1.14
+ go 1.15version diff
checks:
- go test ./...
- go build -trimpath ./cmd/serviceci checks
Component behavior checks
- Render the full synchronized component set.
- Keep copy buttons delegated through GlobalUI.
- Use the blocks in future essays only when they make the reading flow clearer.
Review this Go upgrade note. Keep the prose calm, identify hidden operational risks, and suggest one measurement that would make the rollout easier to trust.
Plain Markdown also participates in the component system:
- —Fenced code uses the editorial code frame.
- —Lists use quiet custom markers.
- —Tables keep their hairline editorial rhythm.
- —Blockquotes are routed into the same quote component as explicit
<C>Quote</C>usage.
type UpgradeNote = {
from: "go1.14";
to: "go1.15";
checks: Array<"test" | "build" | "race" | "smoke">;
};| Surface | Role | Detail |
|---|---|---|
Callout | emphasis | left rule and mono label |
Tabs | variants | keyboard-aware interaction |
References | sources | bidirectional footnote jumps |
PromptBox | reusable text | copyable editorial prompt |
Gallery | visual pacing | typographic placeholders or real images |
Components are not decoration; they are pacing tools for long reading.
Zhaphar
Conclusion.
Go 1.15 is a grounded release: faster linking, lower memory use, cheaper defers, smaller binaries, and a few standard library niceties. The release is worth upgrading to because it lets existing code keep its shape while the platform underneath becomes a little calmer.
— Discussion
GitHubComments.
Comments are powered by GitHub Discussions. Keep the conversation focused and respectful.
Comments did not load this time. Refresh to retry, or join the discussion directly on GitHub.