WebAssembly Value Types Reference

Wasm i32, i64, f32, f64, v128, funcref, externref types with encoding

Reference for WebAssembly core value types — i32, i64, f32, f64, the v128 SIMD vector, and the funcref/externref reference types — with binary opcode, bit width, JavaScript mapping and SIMD lane counts. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

How many value types does core WebAssembly have?

Seven: four number types (i32, i64, f32, f64), one vector type (v128, from the SIMD proposal), and two reference types (funcref, externref). i32 and i64 are integers with no inherent signedness; instructions decide whether a value is treated as signed or unsigned.

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, f64Number
  • i64BigInt (a 53-bit Number cannot hold 64 bits exactly)
  • funcref → a JS function (or null)
  • externref → any JS value passed through unchanged
  • v128 → 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 layoutDescription
i8x1616 signed/unsigned 8-bit integers
i16x88 signed/unsigned 16-bit integers
i32x44 signed/unsigned 32-bit integers
i64x22 signed/unsigned 64-bit integers
f32x44 single-precision floats
f64x22 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 i64 needs BigInt on the JS side causes silent 0n coercions or TypeError.
  • Treating i32 as a signed 32-bit integer always: operations like i32.lt_u interpret 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 v128 to be returnable to JavaScript — it is not; extract lanes first.