The basics
What is a WASM file?
A .wasm file holds a WebAssembly module: functions compiled into a compact binary instruction format, plus a description of what the module needs from outside (imports) and what it offers (exports). It is the output of a compiler. People write C, C++, Rust, Go, C#, Zig or AssemblyScript, and the toolchain produces the .wasm file.
Browsers run it next to JavaScript, which is why photo and video editors, games, CAD tools, PDF viewers and databases can run inside a web page at speeds close to native code. The W3C called it the fourth language of the web, after HTML, CSS and JavaScript, when it became a Recommendation in 2019. The same files also run on servers, at the network edge and inside other applications as plug-ins.
Three things a .wasm file is not:
- Not a replacement for JavaScript. In a browser, a module can't touch the page, the network or storage by itself. JavaScript loads it, passes it the functions it imports and calls what it exports.
- Not machine code. The bytes target a virtual stack machine, not a real processor. The engine validates the module and compiles it to the processor it is running on, so one file runs on x86 and ARM alike.
- Not readable text. Open it in a text editor and you see a few recognisable words (export names, embedded strings) among symbols, because most bytes are opcodes and numbers. The readable form is a separate text format, WAT.
Anatomy
What's inside a .wasm file, byte by byte
A module is a short preamble followed by sections. Each section starts with a one-byte id and its length, so an engine can find or skip any of them. Here is our 262-byte sample-module.wasm, compiled from the sample-module.wat source below, split at each section boundary. Numbers are stored in LEB128, a variable-length encoding where small values take one byte.
offset bytes
; preamble: magic number, then version
000000 00 61 73 6D
000004 01 00 00 00
; section 1 (type), 20 bytes
000008 01 14 04 60 02 7F 7F 00 60 02 7F 7F 01 7F 60 01
000018 7E 01 7E 60 00 00
; section 2 (import), 11 bytes
00001E 02 0B 01 03 65 6E 76 03 6C 6F 67 00 00
; section 3 (function), 4 bytes
00002B 03 04 03 01 02 03
; section 5 (memory), 3 bytes
000031 05 03 01 00 01
; section 6 (global), 6 bytes
000036 06 06 01 7F 00 41 28 0B
; section 7 (export), 36 bytes
00003E 07 24 04 06 6D 65 6D 6F 72 79 02 00 03 61 64 64
00004E 00 01 09 66 61 63 74 6F 72 69 61 6C 00 02 05 67
00005E 72 65 65 74 00 03
; section 10 (code), 58 bytes
000064 0A 3A 03 07 00 20 00 20 01 6A 0B 27 01 01 7E 42
000074 01 21 01 02 40 03 40 20 00 42 01 57 0D 01 20 01
000084 20 00 7E 21 01 20 00 42 01 7D 21 00 0C 00 0B 0B
000094 20 01 0B 08 00 41 00 23 00 10 00 0B
; section 11 (data), 46 bytes
0000A0 0B 2E 01 00 41 00 0B 28 48 65 6C 6C 6F 20 66 72
0000B0 6F 6D 20 39 39 68 65 6C 70 65 72 73 2E 63 6F 6D
0000C0 2F 66 69 6C 65 2D 74 79 70 65 73 2F 77 61 73 6D
; section 0 (custom), 52 bytes
0000D0 00 34 05 61 62 6F 75 74 46 72 65 65 20 73 61 6D
0000E0 70 6C 65 20 66 72 6F 6D 20 39 39 68 65 6C 70 65
0000F0 72 73 2E 63 6F 6D 2F 66 69 6C 65 2D 74 79 70 65
000100 73 2F 77 61 73 6D- 1
00 61 73 6DThe magic number
A zero byte, then the ASCII letters
asm. Every core WebAssembly module starts with these four bytes; an engine that doesn't find them stops at once. - 2
01 00 00 00The version
A 32-bit little-endian 1. It stayed 1 through Wasm 2.0 and 3.0, because the newer versions only add features. WebAssembly components (see below) use a different value here.
- 3
01 14A section header
Id
01(the type section) and a length of0x14, 20 bytes. Known sections appear in a fixed order and at most once each; custom sections, id00, can go anywhere. - 4
60 02 7F 7F 00Type section: function signatures
60introduces a function type: 2 parameters, both7F(i32), and 0 results. That's the signature ofenv.log. The other three types use7E(i64) forfactorialand none at all forgreet. - 5
03 65 6E 76 03 6C 6F 67 00 00Import section
The module needs a function the host must provide: module name
env, fieldlog, kind00(function) with type 0. Names are length-prefixed UTF-8. Instantiation fails if the host doesn't pass it. - 6
03 04 03 01 02 03Function section
Declares 3 functions with type indices 1, 2 and 3. Imports are numbered first, so
logis function 0 andaddis function 1. The bodies come later, in the code section, so engines can start compiling them in parallel. - 7
05 03 01 00 01Memory section
One memory, flag
00(no maximum), starting at 1 page of 64 KiB. This is the module's linear memory: one flat, resizable array of bytes that only the module and its host can see. - 8
06 06 01 7F 00 41 28 0BGlobal section
One immutable i32 global. Its initial value is a tiny expression:
41 28isi32.const 40, and0Bends it. - 9
06 6D 65 6D 6F 72 79 02 00Export section
What the outside world can use:
memory(kind02), thenadd,factorialandgreet(kind00, functions 1 to 3). JavaScript sees these asinstance.exports. - 10
07 00 20 00 20 01 6A 0BCode section: the body of add
7 bytes, no extra locals, then the instructions:
local.get 0,local.get 1,i32.add,end. Common instructions are a single opcode byte, which is what keeps modules small. - 11
00 41 00 0B 28 48 65 6C 6C 6F …Data section
An active segment for memory 0, placed at offset
i32.const 0: 40 (0x28) bytes of text,Hello from 99helpers.com/file-types/wasm, copied into memory when the module is instantiated. - 12
00 34 05 61 62 6F 75 74 …A custom section
Id 0, a name (
about) and any bytes. Engines ignore custom sections. Toolchains use them for function names (name), compiler details (producers) and DWARF debug information.
Under the hood
How an engine runs a .wasm file
- 1Decode. The engine checks the magic number and version, then reads the sections in order. Anything malformed is a
CompileErrorbefore a single instruction runs. - 2Validate. Every function is type-checked: each instruction must find values of the right type on the stack, and every branch must target an enclosing block. Code that fails can't be run at all.
- 3Compile. The engine turns the instructions into native code for the current processor. Browsers can do this while the file is still downloading, which is what
instantiateStreamingis for. - 4Instantiate. The host supplies the imports; the engine creates the memory, tables and globals, copies data segments into memory and runs the start function, if there is one.
- 5Call. The host calls exported functions. Values cross the boundary as numbers (i32, i64, f32, f64) or references; strings and arrays travel through linear memory as bytes, which glue code generated by the toolchain usually handles.
Why validation matters
Because every module is checked before it runs, a WebAssembly function can't jump into the middle of other code or call a function with the wrong signature. Out-of-bounds memory access stops execution with a trap instead of reading someone else's data.
Text format
WAT: the text form of a .wasm file
Every module has an equivalent text representation, the WebAssembly Text Format (.wat), written as S-expressions in brackets. It's what you read when you disassemble a .wasm file and what you write when you hand-code a small module. This is the add function from the anatomy above:
(module
(func (export "add") (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add))- WAT to WASM:
wat2wasm add.watfrom WABT, orwasm-tools parse add.wat -o add.wasm. - WASM to WAT:
wasm2wat file.wasmorwasm-tools print file.wasm. Comments and local variable names are lost unless the file has anamecustom section; you get$var0andfunc 3instead. .wastis a superset of WAT used by the specification's test suite, with assertions about what each module should return or reject.wasm-objdump -x file.wasmlists every section, import and export, which is the quickest way to see what a module needs before you try to run it.
Loading it
Loading a .wasm file in a web page
A page fetches the module and instantiates it through the JavaScript API, passing an object with everything the module imports:
const imports = { env: { log: (ptr, len) => { /* … */ } } };
const { instance } = await WebAssembly.instantiateStreaming(
fetch("sample-module.wasm"), // must arrive as application/wasm
imports,
);
instance.exports.add(2, 3); // 5- The MIME type is checked.
WebAssembly.instantiateStreamingandcompileStreamingreject a response unless itsContent-Typeis exactlyapplication/wasm, with no parameters. The fallback is slower:fetch, thenarrayBuffer(), thenWebAssembly.instantiate. - Cross-origin rules apply. The response must be same-origin or allowed by CORS, and pages opened from
file://can't fetch modules at all. Test through a local web server or put the files online. - Content Security Policy. A page with a CSP must include
'wasm-unsafe-eval'inscript-srcbefore it can compile WebAssembly, as MDN's CSP reference explains. - Glue code. Toolchains such as Emscripten (C/C++) and wasm-bindgen (Rust) generate a
.jsfile that does all of this for you. If a project shipsapp.jsandapp_bg.wasm, load the JavaScript file, not the module.
History
WebAssembly versions: 1.0, 2.0 and 3.0
| Version | Status | What it added |
|---|---|---|
| MVP / 1.0 | Design agreed by the Chrome, Edge, Firefox and WebKit teams in February 2017; W3C Recommendation on 5 December 2019 | Integers and floats, functions, one linear memory, one function table, imports and exports |
| 2.0 | Essentially finished around 2022; at the W3C still a Candidate Recommendation Draft | 128-bit vector (SIMD) instructions, bulk memory operations, multiple return values, simple reference types |
| 3.0 | Completed as the new live standard on 17 September 2025 | 64-bit memories, multiple memories, garbage collection, typed references, tail calls, exception handling, relaxed vector instructions, a deterministic profile, custom annotations in WAT, JavaScript string built-ins |
A .wasm file doesn't declare which version it targets; the header says version 1 either way. What matters is which instructions and section types it uses. An engine that meets a feature it doesn't support rejects the module with a CompileError. According to the 3.0 announcement, most major browsers already ship Wasm 3.0; the feature status page tracks each engine.
Garbage collection is what lets languages such as Kotlin and Dart compile to WebAssembly without shipping their own memory manager inside every module.
Beyond the web
Outside the browser: runtimes, WASI and components
Core WebAssembly has no way to open a file or print a line. A host has to provide that through imports. Outside the browser, the common set of imports is WASI, the WebAssembly System Interface, designed by a subgroup of the WebAssembly Community Group:
| What it is | |
|---|---|
| WASI 0.1 (preview 1) | Functions imported from wasi_snapshot_preview1, such as fd_write. Still the most widely supported. sample-wasi-hello.wasm uses it. |
| WASI 0.2 | Launched on 25 January 2024 and rebuilt on the component model, with interfaces such as wasi:http and wasi:filesystem. |
| WASI 0.3 | Released on 11 June 2026. Adds native async (async func, stream<T>, future<T>) to the component model. Wasmtime supports it; support in language toolchains is still arriving. |
A component wraps one or more core modules with typed interfaces, written in an interface language called WIT, so modules built from different languages can pass strings, lists and records to each other. Components use the same .wasm extension but a different header: an empty component built with jco 1.39 starts 00 61 73 6D 0D 00 01 00. Browsers and Node.js can't instantiate one directly (V8 reports expected version 01 00 00 00, found 0d 00 01 00); the jco tool transpiles components into JavaScript plus core modules.
| Runtime | Notes |
|---|---|
| Browsers | Chrome, Edge, Firefox and Safari, through the JavaScript API. |
| Node.js, Deno, Bun | The same JavaScript API; Node.js also has an experimental node:wasi module. |
| Wasmtime, Wasmer, WAMR | Standalone runtimes: wasmtime file.wasm runs a WASI command from the terminal. Wasmtime is also embedded in other programs. |
| Cloudflare Workers and similar edge platforms | Run modules compiled from Rust, Go or C close to users. Cloudflare's documentation describes its WASI support as experimental. |
Troubleshooting
Why won't my .wasm file load?
These are the messages Chromium and Node.js give for the usual problems; Firefox and Safari word them differently but mean the same:
| Error message | Usual cause | Fix |
|---|---|---|
| Incorrect response MIME type. Expected 'application/wasm' | The server sends .wasm as application/octet-stream or text/plain | Map .wasm to application/wasm on the server, or fall back to arrayBuffer() and WebAssembly.instantiate |
| expected magic word 00 61 73 6d, found 3c 21 44 4f | Those bytes are <!DO: the server returned an HTML page, usually a 404 or a single-page app's fallback page | Fix the path; check the response in the Network tab |
| HTTP status code is not ok | instantiateStreaming received a 404 or 500 response | Fix the path or the server |
| Import #0 "env": module is not an object or function | The module imports functions and none were passed | Pass an imports object with every name wasm-objdump -x lists, or load it through its glue code |
| expected version 01 00 00 00, found 0d 00 01 00 | The file is a component, not a core module | Run it in Wasmtime, or transpile it with jco |
| Cross origin requests are only supported for protocol schemes … | The page was opened from file:// | Serve the folder with a local web server, or put it online |
How to
How to open, inspect and convert a .wasm file
- See what's inside:
wasm-objdump -x file.wasm(WABT) lists sections, imports and exports;wasm2wat file.wasmprints the code as WAT. Browser developer tools show a disassembly of loaded modules in the Sources panel. - Run it: in a page, through the JavaScript API; on the command line,
wasmtime file.wasmfor a WASI command, or a few lines of Node.js for a library module. - Decompile it:
wasm-decompile(WABT) produces C-like pseudo-code. The original source can't be recovered: names, types and structure are gone unless the file carries debug information. - Make it smaller:
wasm-opt -Ozfrom Binaryen optimises for size, andwasm-stripremoves custom sections such as names and debug data. - Compile to it:
clang --target=wasm32,rustc --target wasm32-unknown-unknown, Emscripten for C and C++ projects,GOOS=wasip1 GOARCH=wasm go buildfor Go.
Security
Is a .wasm file safe?
WebAssembly was designed to run untrusted code. A module runs in a sandbox: it can only reach the outside world through the functions its host chooses to import, and in a browser it is bound by the same rules as the page's JavaScript, including the same-origin policy. It has no direct access to the DOM, your files, the camera or the network.
- Bugs inside the module still matter. The sandbox protects the host, not the module from itself. A C buffer overflow compiled to WebAssembly can still overwrite other data in the module's own linear memory, as the WebAssembly security notes point out.
- Side channels. Timing attacks against code running in a module are possible, as they are for JavaScript.
- It's still code. A malicious page can use WebAssembly for anything it could do with JavaScript, only faster. Judge a site, not its file formats.
- Opening a
.wasmfile on your computer runs nothing. No operating system executes it on double-click; it needs a runtime and a host that chooses to load it.
Free downloads
Sample WebAssembly files to download
Free sample WebAssembly files for testing servers, MIME types, runtimes, parsers and size limits. Each .wasm file passes wasm-validate and was instantiated in Node.js 22 with its results checked.
What's inside sample-demo.html
The preview shows a page that loads sample-module.wasm and calls its exports. Open sample-demo.html in a text editor and each numbered comment marks one of these parts.
Comment 1: the status line
Reports how the module was loaded: "loaded" when
instantiateStreamingworked, a warning naming the wrongContent-Typewhen only the slower fallback did, and "running from the embedded copy" when the file couldn't be fetched at all.Comment 2: the results table
Filled in by the script with each call and its result, so you can see the module working.
Comment 3: an embedded copy
The same 262 bytes as base64. A sandboxed preview, like the one on this page, or a page opened from
file://can't fetch the.wasmfile, so the page uses this copy instead.Comment 4: the import object
The module imports
env.log(pointer, length). JavaScript reads those bytes from the module's memory and decodes them as UTF-8: the usual way strings leave a module.Comment 5: loading
instantiateStreamingfirst, thenfetchwithWebAssembly.instantiate, then the embedded copy.Comment 6: calling the exports
addreturns an i32, soadd(2147483647, 1)wraps around to −2147483648.factorialtakes and returns an i64, which JavaScript passes as a BigInt (20n).greetcalls back into JavaScript through the import.
All sample WebAssembly files
Demo page that loads the module
sample-demo.html · 7.0 KB (7,196 bytes)
A self-contained page that loads
sample-module.wasmfrom the same folder withinstantiateStreaming, falls back step by step, and shows each export's result. It makes no other requests.- Checking a server sends `.wasm` as `application/wasm`
- Seeing imports, exports and memory in action
Sample module
sample-module.wasm · 262 bytes
The module dissected in the anatomy above: one import (
env.log), an exported memory with a data segment, a global,add,factorialandgreet, and a custom section. Instantiate it with{ env: { log } }.- Testing loaders, parsers and disassemblers
- Teaching the binary format
Its WAT source
sample-module.wat · 2.1 KB (2,139 bytes)
The text-format source of
sample-module.wasm, with numbered comments. Build it withwat2wasm --enable-annotations(the custom section uses Wasm 3.0's annotation syntax) and you get the same 262 bytes.- Learning WAT
- Testing wat2wasm and editors
WASI command
sample-wasi-hello.wasm · 195 bytes
A hand-written WASI 0.1 program that prints
Hello from WASI!and a link back here. Run it withwasmtime sample-wasi-hello.wasmor Node.js'snode:wasimodule. Browsers can't run it without a WASI shim.- Testing WASI runtimes
- Checking standard output handling
Smallest valid module
sample-minimal.wasm · 8 bytes
Only the magic number and the version: no sections, no imports, no exports. It validates and instantiates to an empty set of exports.
- Edge cases in parsers and upload checks
- File-type detection by magic number
100 KB module compiled from C
sample-100kb.wasm · 100 KB (102,400 bytes)
Two C functions (
count_primesandfnv1a) compiled with clang 18, with thename,producersandtarget_featuressections the toolchain adds, padded with a custom section to exactly 102,400 bytes.count_primes(100)returns 25.- Upload and size-limit tests
- Seeing what a compiler's output looks like
Ways to test with them
- MIME type: put
sample-demo.htmlandsample-module.wasmin the same folder online and open the page. A green "loaded" means the server sendsapplication/wasm; a warning names the type it sent instead. - Runtimes:
sample-wasi-hello.wasmshould print one line in Wasmtime or Node.js;sample-module.wasmshould fail with a missing-import error until you passenv.log. - Parsers and file detection:
sample-minimal.wasmis the 8-byte edge case: valid, but with no sections at all. - Upload limits:
sample-100kb.wasmis exactly 102,400 bytes and still a valid module.
Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.
Put it online
Have a .wasm file? Give it a link.
Drop a .wasm file on 99helpers and it gets its own address, served as application/wasm. Opening the link downloads the file; a page on the same 99helpers site can load it with WebAssembly.instantiateStreaming.
Questions
WebAssembly files, frequently asked
What is a .wasm file?
A compiled WebAssembly module: binary code that browsers, Node.js and other runtimes can run safely inside a sandbox. It is usually produced by compiling C, C++, Rust, Go or another language.
How do I open a WASM file?
You don't open it like a document. To see what's inside, run wasm2wat file.wasm or wasm-objdump -x file.wasm from WABT. To run it, load it from a web page with JavaScript, or use a runtime such as Wasmtime for WASI programs.
Why does a .wasm file look like gibberish in a text editor?
Because it's binary: most bytes are opcodes and numbers, not text. Only names and embedded strings are readable. Convert it to the text format with wasm2wat to read it.
What MIME type should a server use for .wasm?
application/wasm, exactly. WebAssembly.instantiateStreaming refuses any other type, including application/octet-stream.
Can I convert a WASM file back to C or Rust?
Not to the original source. wasm2wat gives the exact instructions as text and wasm-decompile gives C-like pseudo-code, but variable names, comments and the original structure are lost unless the file has debug information.
Is WebAssembly faster than JavaScript?
Often, for heavy computation such as image processing, compression or physics, because it is compiled ahead of time with fixed types. For ordinary page code the difference is small, and every call between JavaScript and WebAssembly has a cost.
Can WebAssembly access the DOM?
Not directly. A module can only call functions it imports, so JavaScript has to do the DOM work on its behalf. Toolchains generate that glue code automatically.
What is the difference between WASM and WAT?
Same module, two forms. .wasm is the compact binary that engines run; .wat is the human-readable text format. Tools convert between them without loss, apart from comments.
Is it safe to open a .wasm file?
Opening one on your computer runs nothing. In a browser, WebAssembly runs inside the same sandbox as JavaScript and can only do what the page's own scripts let it do.
Related formats
Other file types explained
Keep going
Related
Sources
- WebAssembly specifications (webassembly.org)
- WebAssembly Core Specification 1.0, W3C Recommendation
- Wasm 3.0 completed (webassembly.org, 17 September 2025)
- WebAssembly Web API (W3C): streaming and the MIME type check
- IANA media type registration: application/wasm
- WASI 0.3 (Bytecode Alliance)
Last reviewed 27 October 2026.