WebAssembly has a deliberately tiny set of value types. This reference lists each one with its
single-byte binary encoding, bit width, JavaScript mapping and — for v128 — the SIMD lane layouts.
How it works
Value types appear in the binary format’s type section and in function signatures. Each is encoded as one byte:
0x7F i32 0x7E i64
0x7D f32 0x7C f64
0x7B v128 0x70 funcref
0x6F externref
The four number types are split into integers (i32, i64) and IEEE-754 floats (f32,
f64). Integers carry no signedness — i32.div_s vs i32.div_u decides interpretation per
instruction. The vector type v128 holds 128 bits reinterpreted as lanes by SIMD instructions.
The two reference types are opaque handles: funcref to a Wasm function, externref to a host
value.
JavaScript boundary
When Wasm functions are called from JS, types map as:
i32,f32,f64→Numberi64→BigInt(a 53-bit Number cannot hold 64 bits exactly)funcref→ a JS function (ornull)externref→ any JS value passed through unchangedv128→ cannot cross the JS boundary directly; it is internal to Wasm SIMD code
Keep this in mind when wiring imports and exports — passing a plain Number where an i64 is
expected throws a TypeError.
Type-by-type notes
i32 and i64
These are the workhorses of WebAssembly integer arithmetic. i32 is by far the most commonly used type — pointer arithmetic, loop counters, boolean flags (0 or 1), and most integer operations use it. The 32-bit width also matches the address space of the Wasm linear memory (which is byte-addressed but bounded by a 32-bit index range in the current standard).
i64 is needed when you need full 64-bit integer range — timestamps in nanoseconds, large file offsets, or values that overflow 32 bits. The JS boundary cost is that callers must pass and receive BigInt values; mixing Number and i64 is a very common source of TypeError at the Wasm/JS interface.
f32 and f64
Both follow IEEE-754. f64 (double-precision) is what JavaScript numbers already are, so a Wasm export returning f64 arrives at the JS side as a plain Number with no precision loss. f32 (single-precision) is often preferred in graphics and signal-processing code where memory bandwidth and SIMD throughput matter more than the extra precision range.
v128
v128 is a 128-bit packed vector, introduced by the Fixed-Width SIMD proposal. It does not have a single fixed interpretation — the same 128-bit register is viewed differently depending on the instruction:
| Lane layout | Description |
|---|---|
| i8x16 | 16 signed/unsigned 8-bit integers |
| i16x8 | 8 signed/unsigned 16-bit integers |
| i32x4 | 4 signed/unsigned 32-bit integers |
| i64x2 | 2 signed/unsigned 64-bit integers |
| f32x4 | 4 single-precision floats |
| f64x2 | 2 double-precision floats |
A v128 value cannot cross the JS/Wasm boundary — it has no JavaScript representation. SIMD lanes must be extracted to scalar types before returning to JS.
funcref and externref
These are the reference types that let Wasm interact with the host world without exposing memory addresses. A funcref is an opaque reference to a callable — it can be stored in a table and later called with call_indirect. An externref is a completely opaque handle to any host value; Wasm can store it, pass it back, and compare it for identity, but it cannot inspect it. This is how frameworks embed JavaScript objects into Wasm data structures safely.
Common mistakes
- Forgetting that
i64needs BigInt on the JS side causes silent0ncoercions orTypeError. - Treating
i32as a signed 32-bit integer always: operations likei32.lt_uinterpret the bits as unsigned, so the same bit pattern can be both a positive unsigned number and a negative two’s-complement signed number depending on the instruction you choose. - Expecting
v128to be returnable to JavaScript — it is not; extract lanes first.