WebAssembly Overview (see WebAssembly & TinyGo section)
Go can target WebAssembly without cgo: the browser path uses GOOS=js GOARCH=wasm with syscall/js, and the server/edge path uses GOOS=wasip1 GOARCH=wasm for WASI hosts.
Search across all documentation pages
Go can target WebAssembly without cgo: the browser path uses GOOS=js GOARCH=wasm with syscall/js, and the server/edge path uses GOOS=wasip1 GOARCH=wasm for WASI hosts.
cgo is unavailable on wasm targets, so interop shifts to JavaScript bridges, WASI imports, or TinyGo for constrained builds.
WebAssembly is a portable alternative to native cgo when you deploy to browsers, edge runtimes, or sandboxed plugins.
Full build pipelines, size tuning, and host comparisons live in the WebAssembly & TinyGo section - this page orients cgo readers on when to pivot.
Quick-reference recipe card - copy-paste ready.
# Browser wasm (syscall/js)
GOOS=js GOARCH=wasm go build -o app.wasm ./cmd/app
# WASI preview1 (servers, wazero, wasmtime)
GOOS=wasip1 GOARCH=wasm go build -o app.wasm ./cmd/appWhen to reach for this:
.wasm with WASI instead of libc.CGO_ENABLED=0 is mandatory and native syscalls are unavailable.A minimal WASI program that writes to stdout (no cgo, no syscall/js).
// cmd/hello/main.go
package main
import "fmt"
func main() {
fmt.Println("hello wasi")
}GOOS=wasip1 GOARCH=wasm go build -o hello.wasm ./cmd/hello
wasmtime hello.wasmWhat this demonstrates:
fmt works on wasip1 via WASI imports linked by the Go wasm runtime.//go:build !wasm.wasmtime, wazero, Spin, etc.), not ./hello.wasm directly.syscall/js exposes JavaScript values and callbacks for GOOS=js; it is not used on wasip1.| Concern | Native cgo | Go wasm |
|---|---|---|
| C libraries | Link .so/.a | Not available; use wasm ports or hosts |
| Browser DOM | Not applicable | syscall/js callbacks |
| File I/O | libc / x/sys | WASI files or JS fs bridge |
| Binary size | Native ELF/Mach-O | .wasm module (gc wasm is larger than TinyGo) |
| Threads | OS threads | Limited wasm threading; check host support |
| Path | Build | Host | Deep dive |
|---|---|---|---|
| Browser | GOOS=js GOARCH=wasm | Browser + wasm_exec.js | syscall/js Go in the Browser |
| WASI server | GOOS=wasip1 GOARCH=wasm | wasmtime, wazero | Compiling with GOOS=wasip1 |
| TinyGo MCU | tinygo build -target=… | Board or wasm | TinyGo for microcontrollers |
//go:build !js && !wasm
package plugin
// cgo-only native implementation//go:build js || wasm
package plugin
// wasm-safe stub or pure Go implementationSplit packages so interop code does not pull import "C" into wasm builds.
wasm_exec.js - Loader errors. Fix: Follow Go wasm wiki wiring for your bundler.net on js/wasm - Restricted by host sandboxes. Fix: Use fetch/WebSocket bridges documented for syscall/js.wasip1 and js tags - Different syscall sets. Fix: Separate main packages or explicit build tags per target.| Alternative | Use When | Don't Use When |
|---|---|---|
| Native cgo service | Need C SDK on Linux servers | Target is browser or wasm-only host |
syscall/js bridge | DOM and browser APIs required | Headless WASI batch jobs |
| TinyGo wasm | Size and MCU constraints dominate | You need full generics/runtime features |
| Rust/C++ wasm module | Team already ships wasm there | Go-only shop wants one language |
| RPC to native sidecar | Heavy C libs stay on Linux | Wasm sandbox is mandatory |
No - WebAssembly builds are pure Go with target-specific syscalls.
Plan interop without import "C".
js targets browsers with syscall/js.
wasip1 targets WASI runtimes with POSIX-like imports, not the DOM.
See WebAssembly & TinyGo in this site - section order 38 in the Go guide manifest.
Start with Go on WebAssembly.
Recent releases improved wasm runtime and memory behavior.
Read Go 1.26 wasm runtime improvements for specifics pinned to this guide.
Microcontrollers, sub-megabyte modules, and embedded wasm.
Use gc wasm when you need full stdlib compatibility and desktop-class hosts.
Yes - wazero is a pure-Go wasm runtime suitable for embedding.
See WASI host runtimes.
Use syscall/js function values and callbacks.
Keep boundaries narrow to avoid leaking goroutines across JS events.
WASI defines filesystem and environment imports; hosts map them to real or virtual resources.
Capabilities vary by runtime configuration.
Yes - business logic in pure Go packages with tagged platform entrypoints.
Keep cgo isolated behind //go:build cgo && !wasm.
No - native OS integration on Linux/macOS/Windows still needs cgo or x/sys.
Wasm is an additional deployment surface.
Gc wasm binaries are often tens of MB uncompressed before gzip.
TinyGo targets orders-of-magnitude smaller when language subset is acceptable.
wasmtime, wazero, and Spin appear in the dedicated section.
Verify versions at build per manifest pins for tinygo and wazero.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026