WebAssembly file format
A compiled WebAssembly binary module.
- MIME type
- application/wasm
- Extensions
- .wasm
- Category
- Executables & bytecode
Magic-number signature
| 0x00000000 | 0061736D | ·asm | 0x00 'asm' |
About the WebAssembly format
A WebAssembly module is the most regular binary format in this catalogue: an eight-byte preamble, then a sequence of sections, each one a single-byte id followed by a LEB128 length and that many bytes of payload. Nothing is at a fixed offset beyond byte eight, but nothing needs to be — a reader walks the sections and can skip any it does not care about, which is what lets a browser start compiling while the rest of the module is still downloading. The known sections must appear in a fixed order, so a validator can reject a malformed module without a second pass.
Header layout, byte by byte
| Offset | Length | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | 00 61 73 6D — a NUL byte followed by the ASCII letters asm. The leading NUL is deliberate: it guarantees the file is not valid text, so a module that arrives through anything that touches text encodings fails at the first byte instead of somewhere unpredictable. |
| 4 | 4 | version | A 32-bit little-endian version, currently 01 00 00 00 — version 1 — and unchanged since the format shipped, because every extension since has been made backwards compatible rather than by bumping this number. |
| 8 | 1 | First section id | One byte naming the section: 0 custom, 1 type, 2 import, 3 function, 4 table, 5 memory, 6 global, 7 export, 8 start, 9 element, 10 code, 11 data, 12 data count. Known sections must appear in ascending order and at most once each, so the first byte after the preamble is usually 1 (types) or 0 (a custom section a toolchain put in front). |
| 9 | variable | Section size (LEB128) | Unsigned LEB128 byte count of the section body — one to five bytes, each carrying seven bits of value with the high bit as a continuation flag. This is the only length field in the format, and every section boundary is found by adding it, which is why nothing after offset 8 has a fixed address. |
| variable | variable | Section body | Vectors of entries, themselves LEB128-prefixed with a count. The next section id begins immediately after the last byte the size field claimed, so summing ids and sizes must land exactly on the end of the file — the format's built-in truncation check. |
| variable | variable | Custom sections (id 0) | A named blob that carries no semantics: the 'name' section holding function names for stack traces, DWARF debug info, producer metadata, and the target-features record. They may appear anywhere between other sections, and stripping them is exactly what a release build does to shrink a module. |
Telling it apart from its neighbours
| Easily confused with | How to tell |
|---|---|
| WAT text | The text form of the same module is source, not a variant of the binary: it begins with an open parenthesis and the word module, and is UTF-8 throughout. Anything starting 00 61 73 6D is the binary form, which is the only form a browser instantiates. |
| GZIP | Practically the most common confusion, because .wasm files are almost always served compressed. A file that begins 1F 8B is a gzip stream, and the wasm magic only appears after decompression. A build artefact saved straight out of a network tab is often gzip with a .wasm name. |
| ELF executable | Both are compiled output for a virtual or real machine, and an emscripten or wasi-sdk build directory contains both — the .o files are ELF while only the final module is wasm. 7F 45 4C 46 versus 00 61 73 6D at offset 0 separates them without ambiguity. |
| asm.js | The ancestor, still found in old bundles: asm.js is JavaScript, a plain text file with a 'use asm' directive, delivered as .js. If a tool loads it with WebAssembly.instantiate it will fail on the magic, because there is no binary module in it at all. |
How these files break
- Truncation. Section sizes are declared before their contents, so a partial download parses correctly right up to the point where a section claims more bytes than remain — the decoder reports 'unexpected end of section or function', which is the clearest truncation message any format in this catalogue produces.
- Served or saved gzip-compressed. A .wasm downloaded with Content-Encoding gzip and written to disk unchanged starts 1F 8B, and WebAssembly.instantiate rejects it on the magic. The bytes are fine; only the layer is wrong.
- A stray byte inside a section body. The section walk still lands on the right boundaries as long as the length fields are intact, so the module often loads and then traps or misbehaves at runtime, which is much harder to diagnose than a header failure.
- Text-mode transfer or an editor that appends a newline. One extra byte at the end leaves a module whose section walk ends one byte short of the file, and strict decoders report trailing bytes rather than accepting it.
Where the format stands today
WebAssembly is how existing native code reaches the browser: video and image codecs, PDF and CAD engines, SQLite, Python and Ruby runtimes, emulators, and the compression libraries behind in-browser archive tools all ship as .wasm modules. It is not a replacement for JavaScript and is not used for UI — it has no DOM access of its own — but it is the default answer for compute-heavy work that must run on the user's machine, which is also what makes browser-only, no-upload tools possible at all. Outside the browser it has grown a second life as a portable sandbox: WASI runtimes, edge compute platforms and plug-in systems all use the same binary format, which is why a module built for a website often runs unchanged on a server.
Open WebAssembly files on this site
Every one of these runs in your browser — the file never leaves your machine.
Related formats
Formats that are easy to confuse with WebAssembly — compare their leading bytes.
| Format | First bytes | Extension |
|---|---|---|
| ELF executable | 7F 45 4C 46 | .elf |
| Java class file | CA FE BA BE | .class |