Reading Exports
After instantiation, instance.exports is a plain JavaScript object. Every symbol the WAT module explicitly exports appears as a property on it — exported functions are callable, exported memory is a WebAssembly.Memory, and exported globals are WebAssembly.Global objects.
Exported functions
Section titled “Exported functions”Exported Wasm functions behave like ordinary JavaScript functions. You call them, pass JavaScript numbers as arguments, and receive JavaScript values back. The mapping for most numeric types is straightforward: i32, f32, and f64 all arrive in JavaScript as number.
(module (func (export "add") (param $a i32) (param $b i32) (result i32) local.get $a local.get $b i32.add))const { instance } = await WebAssembly.instantiate(bytes, {});console.log(instance.exports.add(10, 32)); // 42Number marshalling — i64 and BigInt
Section titled “Number marshalling — i64 and BigInt”JavaScript’s number type is IEEE-754 double precision, which can represent integers exactly only up to 2^53 − 1 (Number.MAX_SAFE_INTEGER). The Wasm i64 type is a full 64-bit integer and can hold values far beyond that range.
To avoid silent precision loss, the WebAssembly JS API converts i64 return values to JavaScript BigInt rather than number. The result of calling a function that returns i64 will have typeof result === 'bigint', not 'number'.
(module (func (export "bignum") (result i64) i64.const 9007199254740993))const result = instance.exports.bignum();console.log(result); // 9007199254740993nconsole.log(typeof result); // "bigint"Note that arithmetic between BigInt and number requires explicit casting — you cannot mix them with operators like + or * without converting first.
Exported globals
Section titled “Exported globals”A Wasm module can export globals alongside functions. An exported global is accessed in JavaScript as a WebAssembly.Global object; its current numeric value lives at the .value property.
(module (global (export "PI") f64 (f64.const 3.14159)))console.log(instance.exports.PI.value); // 3.14159Exported memory
Section titled “Exported memory”When a module exports its linear memory, JavaScript receives a WebAssembly.Memory object. The raw bytes are accessible through its .buffer property as an ArrayBuffer, which you can wrap in typed array views to read or write individual bytes.
(module (memory (export "mem") 1))const mem = instance.exports.mem; // WebAssembly.Memoryconst view = new Uint8Array(mem.buffer);console.log(view.length); // 65536 (1 page = 64 KiB)Run it
Section titled “Run it”The module below exports an add function, a bignum function that returns an i64 beyond Number.MAX_SAFE_INTEGER, and a VERSION global. The runner reads all three and logs their values and types.
Trade-offs
Section titled “Trade-offs”| Option | Benefit | Cost |
|---|---|---|
instantiateStreaming | Compilation starts the moment bytes start arriving from the network, so exports are ready sooner | Depends on the server correctly setting Content-Type: application/wasm, or it rejects immediately |
instantiate on a full buffer | Simpler, straightforward control flow; works even without control over the server’s MIME type | Has to wait for the full download before compiling, so exports are ready later |
Common mistakes
Section titled “Common mistakes”- Forgetting to convert an
i64result toBigIntbefore mixing it with a plainnumber, causing a thrownTypeErroror a silently wrong value - Reading or writing large chunks of exported memory byte-by-byte or call-by-call instead of wrapping
.bufferin a typed array view and reading/writing it in one pass, losing performance for no reason - Loading the whole file with
arrayBuffer()first and instantiating afterward to reach the exports, instead of usinginstantiateStreamingto compile while it downloads
💡 Real-world example
Squoosh, Google’s browser image-compression tool, compiles codecs like MozJPEG, WebP, and AVIF to Wasm and calls their exports directly from JS, reading the resulting image bytes back out through exported memory for maximum throughput.