# WebAssembly with Elide

> Run WASI command modules with Elide, map host directories, load WebAssembly libraries from JavaScript and TypeScript, and check supported proposals.

WebAssembly support is experimental in 1.6.0.

| You have | Use | Result |
| --- | --- | --- |
| A WASI command | `elide run app.wasm` | Runs the module with WASI Preview 1 imports. |
| A WASM library | The `WebAssembly` API or an ES module import from JS/TS | Exposes the module's exports. |

<img src="https://elide.help/assets/demos/wasm.gif" alt="elide app.wasm — WASI commands and WASM libraries from JavaScript" width="1591" height="546" loading="lazy" decoding="async" class="rounded-lg border border-border my-6 w-full" />

To compile Java or Kotlin to WebAssembly, see [WebImage](https://elide.help/docs/toolchain/jvm/webimage); its output needs its JavaScript
loader, not `elide run`. Target guides: [Browser WASM](https://elide.help/docs/toolchain/web/wasm) and [Edge WASM](https://elide.help/docs/toolchain/edge/wasm).

## Run a WASM file

```bash
elide run app.wasm
elide app.wasm
elide run app.wasm -- first second   # program arguments
elide run --timeout=5s app.wasm      # exit 124 after 5 seconds
```

Elide calls the exported `_start`, or `_main` if `_start` is absent. Load a module with neither from JavaScript.

| Behavior | Value |
| --- | --- |
| Argument zero | The module's absolute path. |
| Exit status | Set by WASI `proc_exit`, not by a function's return value. |
| Traps, malformed binaries | Nonzero exit. |
| `--timeout` | Covers instantiation and execution; exits `124`. |

### Project entrypoints

Set the module as the entrypoint in `elide.pkl`, then run `elide run`:

```pkl
amends "elide:project.pkl"
name = "wasm-app"
entrypoint { "app.wasm" }
```

See [Project setup](https://elide.help/docs/projects).

## WASI

Commands get WASI Preview 1 imports under `wasi_snapshot_preview1`: standard streams, arguments, exit status, and
filesystem operations. Libraries loaded from JavaScript do not get WASI.

### Directory access

WASI commands see no host directories until you map one:

```bash
elide -Xpolyglot.wasm.WasiMapDirs=work::./data run app.wasm
```

This maps `./data` to the guest directory `work`. Separate mappings with commas: `work::./data,output::./results`.

The sandbox still applies. WASI file opens need read and write permission, even for reads:

```bash
elide -Xpolyglot.wasm.WasiMapDirs=work::./data run \
  --sandbox --allow-read=./data --allow-write=./data app.wasm
```

See [Sandbox and Limits](https://elide.help/docs/sandbox).

## JavaScript and TypeScript interop

The global `WebAssembly` API needs no flag:

```javascript
import { readFile } from "node:fs/promises";

const bytes = await readFile(new URL("./math.wasm", import.meta.url));
const { instance } = await WebAssembly.instantiate(bytes, {});
console.log(instance.exports.add(20, 22));
```

Modules loaded from JavaScript do not run `_start` or `_main`. The second argument supplies the module's imports:

```javascript
const imports = { env: { log: (value) => console.log(value) } };
const { instance } = await WebAssembly.instantiate(bytes, imports);
```

The API includes `validate`, `compile`, `Module`, `Instance`, `Memory`, `Table`, `Global`, and import and export
inspection. A compiled `Module` can be instantiated more than once. File reads follow the usual permissions.

### ES module imports

```javascript
import { add } from "./math.wasm";
console.log(add(20, 22));
```

```javascript
const math = await import("./math.wasm");
console.log(math.add(20, 22));
```

Specifiers can be paths, `file:` URLs, or package exports that resolve to `.wasm`. A source-phase import returns
the compiled module to instantiate yourself:

```javascript
import source mathModule from "./math.wasm";
const math = await WebAssembly.instantiate(mathModule, {});
console.log(math.exports.add(20, 22));
```

## Supported WebAssembly proposals

On by default, for commands and JS/TS interop:

- Mutable globals and sign-extension operators
- Non-trapping float-to-integer conversions
- Multi-value function and block results
- Bulk memory operations and reference types
- Multiple memories
- Extended constant expressions
- Exception handling
- Typed function references
- Garbage-collected types (WasmGC)
- Tail calls
- Fixed-width SIMD (`v128`) and relaxed SIMD, except with Python installed

Off by default:

| Proposal | Option | Notes |
| --- | --- | --- |
| Memory64 | `wasm.Memory64` | Also requires `wasm.UseUnsafeMemory`. |
| Threads and atomics | `wasm.Threads` | No WASI thread-spawning host API is supplied. |
| Wide integer arithmetic | `wasm.WideArithmetic` | Separate from ordinary `i64` arithmetic. |
| Legacy exception handling | `wasm.LegacyExceptions` | The newer exception-handling proposal is on by default. |

Enable one with `-Xpolyglot.<option>=true`, for example `-Xpolyglot.wasm.WideArithmetic=true`. This does not
supply the host imports a module needs.

## Limits

- **Binary modules only.** No `.wat`, no compiling C or Rust, no WASM REPL.
- **WASI Preview 1 only.** No WASI Preview 2, component model, or `node:wasi`; no general network access.
- **Host imports.** `elide run` supplies only WASI, not browser APIs or Emscripten glue.
- **SIMD with Python.** With Python installed, SIMD modules are rejected. Use an install without Python or a scalar
  build of the module.

## Samples

- [WebAssembly from JavaScript](https://elide.help/docs/code-samples#webassembly-from-javascript)
- [WASI command](https://elide.help/docs/code-samples#wasi-command)
