Golang for WebAssembly Can Now Work Like IT Should
The promise of WebAssembly lies in its ability to provide modules so that code written in any programming language can be compiled into a WebAssembly module and distributed in binary format to any CPU device running its instruction sets. This means developers can write in the language of their choice, compile to WebAssembly, and deploy to thousands of devices — whether servers, edge devices or any CPU-based systems — with a single click.
While WebAssembly has historically performed exceptionally well in the browser, the broader application of this technology remains a work in progress. Languages like C++ and Rust are particularly well-suited for WebAssembly. However, this leaves out one of the most important and accessible languages: Go.
Thanks to the WASI component model and significant advancements in Go, especially with TinyGo, it is now possible to use Go in the WebAssembly context, deploying on WASI-compatible modules. Go currently relies on TinyGo for compilation, and this dependency is likely to continue, which is not necessarily a drawback.
For those eager to use WebAssembly with Go, this is a significant milestone. The integration works, or at least has been shown to work, fulfilling WebAssembly’s promise of broader support for various programming languages across devices beyond the browser.
Considerable effort has gone into developing the Go bindings, enabling Go to integrate and interact with TinyGo’s libraries for seamless functionality. As noted, TinyGo’s role is mostly behind the scenes. The “Wasm + Tools for Go” project documentation states that the repository provides code to generate Go bindings for Component Model interfaces defined in WIT (WebAssembly Interface Type) files. The goal of this project is to accelerate the adoption of the Component Model and the development of WASI 0.2+ in Go.
“Before this release, Go developers were writing Wasm apps, but now they can write Go apps, and converting them into Wasm is just a compiler flag away,” said Eric Gregory, senior technical writer at Cosmonic and wasmCloud maintainer, who gave a shout out to Fastly’s Randy Reddig for his wasm-tools-go work in a blog post. “This demonstrates how aligning on a common standard improves the experience for native language toolchains because they have a common ABI [Application Binary Interface] to target. Developers can write ordinary Go code and get the interoperability of components ‘for free.’ With the toolchain in place, there’s a smooth, accelerated developer experience for components, and across languages, those toolchains are now taking shape.”
Compiling Go + TinyGo to Wasm allows developers to write their code in Go, with TinyGo supporting the necessary libraries for WebAssembly compilation. The WASI interfaces remain transparent. As Gregory showed in a blog post, code written in Go using the go-jq CLI can be compiled to the WASI component target with the following command: <tinygo build -o gojq.wasm -target=wasip2 ./cmd/gojq/main.go>.
The built component can then be run with WASI P2-compatible WebAssembly, as demonstrated with Wasmtime: <echo ‘{“value”:”foo”}’ | wasmtime –wasm component-model ./gojq.wasm -r .value.>
TinyGo’s Time
It appears TinyGo will continue to support Go indefinitely. Go on its own for WebAssembly still has limitations. TinyGo’s creator, Ron Evans, noted that while TinyGo covers the full Go language, it uses a different compiler, written in Go but also leveraging LLVM. “Big Go,” as Evans describes it, does have some WASM support, but with inherent limitations and drawbacks.
The binary size with TinyGo is substantially smaller compared to Go code, by a factor of seven to ten, Evans said. “More importantly, TinyGo has been leading the way for new features in WASM/WASI, such as the WASI component model,” he added.
Additionally, the presence of a stable standard with production usage “makes the difference here,” said Bailey Hayes, CTO at Cosmonic, WASI Subgroup co-chair, and technical steering committee director of the Bytecode Alliance. Interestingly, Go lacks a more nimble production cadence compared to TinyGo. “With WASI P2 in place, languages can move to support it, and we’re seeing the benefit of that now,” Hayes said. “TinyGo operates on a quick release cycle, whereas ‘Big’ Go is twice yearly, so this feature is showing up in TinyGo first and is slated for the next timed release of Go.”
That said, TinyGo can shine on its own. During the Wasm I/O conference in Barcelona earlier this year, Evans demonstrated that substantial development is going into TinyGo for Wasm, particularly with its compatibility with open-source Mechanoid, a framework for WebAssembly applications on embedded systems and IoT devices.
Component Story
A WebAssembly component is crucial for deploying runtimes within WebAssembly modules, though its standardization is still in progress.
Once finalized, the component model will enable WebAssembly to expand its use beyond web browsers and servers. It will allow users to deploy various applications within lightweight modules at high speeds across thousands of endpoints simultaneously, using the WebAssembly System Interface (WASI), all without altering a single line of code.
This model is often likened to Lego blocks, where components serve as interfaces through WASI, enabling WebAssembly modules to provide runtimes. These components can be stacked together, linking them to combine the versatility and power of different WebAssembly runtimes into a unified package or unit.
The ability to port Go code to WebAssembly modules is likely to improve support for other languages, such as Python for AI, thanks to ongoing Wasi P2 development. According to Hayes, it was challenging to compile Go to Wasm components before new APIs and semantics were introduced in WASI P2.
“Creating an SDK that natively supports WASI P2 is something all languages will benefit from, not just Go,” Hayes said. “We’re excited because, along with Rust and .NET, we’re seeing Golang add native support.”
And the work continues. “Language libraries and toolchains commit to several years of support, so landing changes at this layer requires a high degree of stability and commitment,” Hayes said. “The component model standard landed in January of this year, so it’s pretty exciting that we’re already seeing standard language toolchains align to it and be able to produce a component as a standard compile target.”