How to Compile Go to Optimized Wasm

WebAssembly (Wasm) allows developers to run Go code in the browser and other environments at near-native speeds. While the standard Go compiler supports Wasm compilation, the resulting binaries can be quite large. This article explores the primary tools available to translate Go code into WebAssembly, specifically focusing on how to achieve highly optimized, lightweight Wasm binaries using TinyGo and optimization utilities like wasm-opt.

1. The Standard Go Compiler (Go upstream)

The official Go compiler (gc) includes native support for compiling Go code to WebAssembly.

To compile a Go program using the standard toolchain, you set the target operating system to js and the architecture to wasm:

GOOS=js GOARCH=wasm go build -o main.wasm main.go

2. TinyGo (The Ideal Optimizer)

TinyGo is an alternative compiler for Go designed specifically for use in small places like microcontrollers and WebAssembly. It leverages LLVM to optimize code and strips out unused runtime features, making it the premier tool for generating highly optimized Wasm binaries.

To compile a Go program using TinyGo, use the following command:

tinygo build -target=wasm -o main.wasm main.go

3. Binaryen and wasm-opt

To further reduce the size and increase the execution speed of a compiled Wasm binary, developers use wasm-opt. This is a tool from the Binaryen toolkit, which is a WebAssembly-specific compiler infrastructure library.

Once you have generated a .wasm file using either Go or TinyGo, you can run wasm-opt to perform passes that optimize the WebAssembly bytecode:

wasm-opt -O3 main.wasm -o optimized.wasm

You can also optimize specifically for size using the -Oz flag:

wasm-opt -Oz main.wasm -o optimized.wasm

This tool removes redundant code, optimizes loops, and compresses the binary structure, shaving off up to 20% to 50% more of the file size.

Choosing the Right Toolchain