Go Brings a Different Set of Assumptions to Lambda

With AWS adding Go support to Lambda in early 2018, the serverless lineup gained a language with a different philosophy than the existing options. The supported runtimes at the time were Node.js (v4.3.2 and 6.10.3), Java 8, Python (3.6 and 2.7), .NET Core (1.0.1 and 2.0), and Go 1.x. What stands out is what's missing: no Java 9, and no recent major Node.js releases (7.x, 8.x, or 9.x).

That gap says something about how Lambda operates. New runtimes are costly to create and maintain, so supported versions lag public releases by a significant margin. One notable example: async/await, available in Node since roughly version 7.6, still wasn't on Lambda a year after it landed upstream.

Prompt for creating a new function on Lambda.
Prompt for creating a new function on Lambda.

The Longevity of the 1.x Line

Lambda's "Go 1.x" runtime label looks similar to the others, but the underlying reality is different. Go 1 shipped in March 2012, nearly six years before this announcement. Nine point releases followed, each bringing meaningful features and improvements, and a tenth was expected shortly.

Despite that velocity, the Go team has maintained compatibility throughout. The official compatibility document states the intent clearly: programs written to the Go 1 specification should continue to compile and run correctly through future point releases. The APIs may grow, but should not break existing code.

It is intended that programs written to the Go 1 specification will continue to compile and run correctly, unchanged, over the lifetime of that specification. At some indefinite point, a Go 2 specification may arise, but until that time, Go programs that work today should continue to work even as future "point" releases of Go 1 arise (Go 1.1, Go 1.2, etc.).

This goes beyond semantic versioning. Semver provides rules for handling breaking changes when they happen; it says nothing about committing to avoid them altogether. Go's track record gives Lambda users a reasonable expectation that the Go runtime will outlive the others on the list, probably by years.

Static Binaries Simplify the Deployment Story

The standard Lambda deployment flow for Go involves compiling a statically-linked binary, zipping it, and uploading the package. That contrasts with source-level languages like Node.js and Python, and with bytecode approaches like Java and .NET Core.

$ GOOS=linux go build -o main
$ zip deployment.zip main
$ aws lambda create-function ...

Static linking eliminates the need for a dependency deployment system at runtime. Everything the program needs is already in the binary, so there are no include paths, requirements files, or project layout concerns once execution starts. While Go's dependency management has been a long-standing weak point, the vendor/ directory introduced in Go 1.6 and the newer dep tool address much of that criticism.

There's also a forward-compatibility angle. When a new Go version ships, AWS may not need to update its runtime for existing binaries to run, assuming the net/rpc package used by aws-lambda-go for its entrypoint remains stable. That package has been frozen for over a year, and its serialization format, encoding/gob, explicitly commits to forward compatibility. In contrast, Node users on Lambda were still transpiling to get async/await.

Stability as a Feature

Most software projects require periodic maintenance and upgrades, often with painful migrations involved. Go represents a different model: the language continues to evolve actively while maintaining a stable core. There has been discussion about a possible Go 2.0, but no concrete breaking-change plans exist.

The practical benefits for Lambda are clear. The language already offers strong runtime performance, good concurrency primitives, a solid standard library, and a fast edit-compile-debug cycle. The addition of long-term API stability and trivial deployment packaging makes Go a strong candidate for new serverless functions.