Showing Posts From

Cloud

Go's Quiet Dominance: The Language That Now Runs Cloud Infrastructure

Go's Quiet Dominance: The Language That Now Runs Cloud Infrastructure

Go doesn't have evangelists the way Rust does. Nobody is writing passionate blog posts about how Go's type system changed how they think about software. The language's community is, by design, pragmatic to the point of being slightly boring. And yet Go now runs more of the internet's infrastructure than any other language that has emerged in the last fifteen years. This is not an accident, and it's worth understanding why it happened. The Catalog Start with the software. Kubernetes is written in Go. Docker is written in Go. Terraform is written in Go. Prometheus is written in Go. Grafana's backend is written in Go. The etcd distributed key-value store that most of the cloud-native ecosystem depends on is written in Go. CockroachDB is written in Go. Istio, Envoy's control plane, most of the CNCF project catalog — Go. This is not a list assembled to make a rhetorical point. It is the actual technology stack of cloud-native infrastructure, and it is almost uniformly written in one language. If you're running Kubernetes clusters — and most organizations building software at scale are — you are running Go code. The question is why this happened, and the answer is both technical and cultural. What Go Got Right When Google open-sourced Go in 2009, the design goals were explicit: fast compilation, simple concurrency, straightforward deployment, readable code that a large team could maintain without constant style arguments. These were not ambitious goals in a research sense. They were engineering goals, chosen by people who had spent years maintaining massive codebases in C++ and Java and knew exactly what problems they wanted to avoid. Go's goroutines and channels made concurrent network programming genuinely approachable. Before Go, writing a service that needed to handle thousands of simultaneous connections required either callbacks (Node.js, with all the callback-hell problems that implied) or threads (Java, with the overhead and complexity that implied). Goroutines are lightweight — you can have hundreds of thousands of them — and the channel model for communication between them eliminated whole categories of concurrency bugs without requiring a PhD in concurrent programming. The single-binary deployment story was underappreciated at first and became one of Go's most important practical advantages as containerization took off. A Go service compiles to a single static binary with no runtime dependencies. Containerizing it means writing a FROM scratch Dockerfile with one line. Operational simplicity at this level compounds over time. The toolchain was opinionated in ways that turned out to matter. gofmt enforced a single code style, eliminating code review debates about formatting permanently. The built-in testing framework meant everyone used the same testing conventions. The race detector shipped with the standard library. These choices made large codebases — and especially codebases maintained by large, rotating teams — much easier to manage. The Generics Question, Finally Answered For years, Go's biggest technical complaint was the absence of generics. The workarounds — using interface{}, using code generation, duplicating implementations for different types — were genuinely painful, and there was a real argument that Go's simplicity was partly an illusion: you paid for it in boilerplate. Generics landed in Go 1.18 in 2022, and the reception was complicated. The implementation was initially slow, the syntax was controversial, and a significant part of the community thought Go had made a mistake. That debate mostly resolved over the following two years. By Go 1.22 and 1.23, the generics implementation was performant, the standard library had been updated to use generics thoughtfully, and idiomatic generic code became possible without fighting the type system. The pattern that emerged was sensible: generics in Go are not the centerpiece of the language the way templates are in C++ or generics are in Haskell. They're used where they clearly add value — collection utilities, generic data structures, functional helpers — and the rest of the code stays concrete and readable. Go didn't become Scala. It became a slightly more expressive version of itself, which is exactly what the language needed. Enterprise Adoption Crossed a Threshold The most significant development for Go in 2025 was not technical. It was the completion of a shift in where Go gets used. For most of Go's history, the main users were companies that were primarily software companies — the Googles and Discords and Cloudflares of the world, organizations whose engineering teams are large and sophisticated enough to evaluate a language and make a deliberate choice. These organizations adopted Go early and drove much of its ecosystem development. In 2025, Go's adoption crossed into organizations where software is not the primary business. Financial institutions building internal services. Retailers building platform infrastructure. Healthcare companies building data pipelines. These organizations don't pick languages for ideological reasons — they pick them because the tooling is mature, the talent pool is sufficient, the operational story is simple, and the code is maintainable by teams that have turnover. Go satisfies all of those requirements. It's learnable by a competent engineer in weeks, not months. It has a rich standard library that covers most of what these organizations actually need. The cloud SDKs — AWS, GCP, Azure — are all first-class. And the output is deployable infrastructure that the organization can actually operate and maintain. What the Language Looks Like in 2025 Go 1.23 shipped range-over function iterators, which cleaned up one of the remaining ergonomic rough edges in the language. The toolchain continued to improve, with faster builds and better IDE tooling through the gopls language server. The ecosystem matured in parallel. Libraries for the major use cases — HTTP services, gRPC, database access, message queues, observability — are well-maintained and production-tested. The Go module system, which had a rocky introduction but stabilized quickly, made dependency management reliable enough that it largely stopped being a source of operational pain. The one persistent complaint — error handling — remains unresolved. The if err != nil pattern that permeates Go code is verbose and creates repetitive code in any function that calls multiple fallible operations. Various proposals for improving this have circulated for years and none have been accepted. The Go team's position is that explicit error handling is worth the verbosity because it makes control flow obvious. Large portions of the community disagree. This argument will apparently continue indefinitely. Where Go Fits in 2025's Language Landscape Go is not trying to be Rust. It is not trying to be Python. The language has a clear thesis — networked services, infrastructure tooling, systems that need to be fast and concurrent but don't need to manage memory at the level of an OS kernel — and it executes on that thesis well. The interesting dynamic in 2025 is the convergence of Go and Rust in the same organizations. Companies building cloud infrastructure are often running Go services on top of systems components written in Rust. The AWS example — Lambda's Firecracker runtime is Rust; most of the control-plane tooling is Go — is being replicated at many other organizations. The two languages are complementary, not competitive, and knowing both is increasingly the mark of a well-rounded systems engineer. Go's trajectory is steady in a way that is sometimes mistaken for stagnation. The language is not going to surprise you. It is going to work reliably, compile quickly, and deploy cleanly, and the code you write today will be readable by an engineer who joins your team in three years. For organizations building and operating infrastructure, that is exactly what the language is supposed to do.