Inside WebAssembly
The format, the machine and the host, for people who compile to it
Written for WebAssembly 3.0, checked against Node 22, wabt 1.0.39 and Wasmtime 50, November 2026
A book about WebAssembly for programmers who want to generate it: the stack machine, the module structure, the binary encoding, the JavaScript host, the post-MVP features, and how to test a compiler that targets it. Every example in it is assembled, validated and run as part of building the book, and the output shown is the output the tools gave.
Download
- Print — Letter, double-sided, notes in the outer margin, 3.6 MB
- Mobile — small pages for reading on a phone, 3.3 MB
- Mobile, dark — the mobile layout on a dark background, 3.3 MB
Contents
- Part IGetting Started
The first five chapters set up the machine. You will write modules by hand in the text format, run them in the same engine a browser uses, and learn the handful of ideas everything else is built on: a typed operand stack, four number types whose signedness lives in the instructions, and functions whose call stack you cannot see.
- 1Introduction
- 2Hello, WebAssembly
- 3A Stack Machine
- 4Numbers
- 5Functions
- Part IIStructure
Native code jumps wherever it likes. WebAssembly code cannot: its control flow is nested blocks and loops, and a branch can only leave a block or restart a loop. The first two chapters of this part show how that works and how a compiler fits a language's control flow into it, including the control flow that does not fit naturally. The third steps back to look at a module as a whole: what it can contain, how its parts are numbered, and how it connects to the outside world.
- 6Structured Control Flow
- 7Control Flow Graphs
- 8Modules and Instances
- Part IIIMemory and Indirection
A WebAssembly function can keep values in locals and on the operand stack, but anything with an address lives in linear memory: one flat array of bytes per memory, bounds-checked on every access. This part covers the instructions that use it, how a compiler lays out a language's data and its stack inside it, and the two other kinds of state a module has: globals, and the tables that make indirect calls possible.
- 9Linear Memory
- 10Laying Out Memory
- 11Globals and Tables
- Part IVThe Binary Format
Everything so far has been written in the text format and turned into bytes by an assembler. A compiler usually skips the text and writes the bytes itself, which is simpler than it sounds: the binary format was designed to be easy to produce and fast to decode. This part goes through it from the first byte to the last, writes a module in hex by hand, builds a small encoder, and covers the optional sections that carry names and debugging information.
- 12Bytes on the Wire
- 13Encoding Instructions
- 14Custom Sections and Debugging
- Part VThe Host
A WebAssembly module on its own can compute, but it cannot see or do anything: every effect goes through its host. In a browser, the host is the JavaScript engine. This part covers the JavaScript API for compiling and instantiating modules, the rules for converting values at the boundary, the patterns for moving strings, arrays and callbacks across it efficiently, and what happens when a module traps.
- 15The JavaScript API
- 16Across the Boundary
- 17Traps
- Part VIBeyond the First Version
WebAssembly 1.0 was deliberately minimal. Everything in this part came later: SIMD for numeric code, exception handling, tail calls, garbage collected structs and arrays, and shared-memory threads. Each one changes what a compiler can emit, and some change how a whole language should be mapped onto WebAssembly. The part starts with how to find out which of them the engine you are running on supports.
- 18Versions and Feature Detection
- 19SIMD
- 20Exceptions
- 21Tail Calls
- 22Garbage Collection
- 23Threads and Atomics
- Part VIICompiling to WebAssembly
The earlier parts described the machine one feature at a time. This part looks at it from the compiler's side. The first chapter goes through the decisions involved in mapping a language onto WebAssembly, from scalar types to calling conventions to coroutines, with a worked example. The second explains how engines turn a module into machine code, and what that means for the code your compiler should emit.
- 24Mapping a Language onto WebAssembly
- 25Performance
- Part VIIITesting
A compiler that emits WebAssembly has more ways to be wrong than most programs: it can write malformed bytes, invalid code, valid code that computes the wrong thing, or correct code that one engine runs differently from another. The good news is that the WebAssembly ecosystem has excellent tools for catching each kind of mistake. This part covers the specification's own test format, then builds a layered testing strategy for a compiler on top of existing tools.
- 26The Spec's Test Format
- 27Testing a Compiler
- AInstruction Reference
- BTools
- CFurther Reading
The diagrams, text and examples are original. The fonts are Lora, JetBrains Mono and Patrick Hand, under the SIL Open Font License; their licences are in fonts/.