Skip to content

Your First WASM Module

Let's build a simple but complete WebAssembly module. We'll use WebAssembly Text Format (WAT) to clearly demonstrate.

Write WAT Code

Create add.wat:

wat
(module
  ;; Define an add function
  (func $add (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add)

  ;; Export function
  (export "add" (func $add)))

Compile to Binary

Compile with wat2wasm:

bash
wat2wasm add.wat -o add.wasm

Use in JavaScript

Create index.html:

html
<!DOCTYPE html>
<html>
<head>
    <title>First WASM Module</title>
</head>
<body>
    <h1>My First WASM Module</h1>
    <div id="result"></div>

    <script type="module">
        async function loadWasm() {
            const response = await fetch('add.wasm');
            const bytes = await response.arrayBuffer();
            const { instance } = await WebAssembly.instantiate(bytes);

            const result = instance.exports.add(40, 2);
            document.getElementById('result').textContent = `Result: ${result}`;
        }

        loadWasm();
    </script>
</body>
</html>

Modern Loading: Streaming Compilation

For better performance, use instantiateStreaming:

javascript
const response = await fetch('add.wasm');
const { instance } = await WebAssembly.instantiateStreaming(response);
// Directly from promise — no arrayBuffer needed

Add More Functions

Expand our module:

wat
(module
  ;; Add function
  (func $add (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add)

  ;; Subtract function
  (func $sub (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.sub)

  ;; Multiply function
  (func $mul (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.mul)

  ;; Divide function
  (func $div (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.div_s)

  ;; Conditional: check equality
  (func $isEqual (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.eq)

  ;; Export all functions
  (export "add" (func $add))
  (export "sub" (func $sub))
  (export "mul" (func $mul))
  (export "div" (func $div))
  (export "isEqual" (func $isEqual)))

Understanding Syntax

InstructionDescription
local.getPush local variable onto stack
i32.addPop two values, add, push result
param $name typeDeclare function parameter
result typeDeclare return type
export "name"Export function for JavaScript

What's Next

You've built your first WASM module! Next, learn how to compile with Rust for more complex projects.

Challenge

Try creating a WASM module that calculates the Fibonacci sequence. Test it with different values!

Released under the MIT License.