Write a function in C, compile it to WebAssembly, and call it from Node.js (or Bun) and the browser. No Emscripten, no bundlers, just clang and pure WASM.
This guide works on macOS Tahoe as of 2026, and on modern Linux distros.
You need a clang that supports the wasm32 target and the LLVM linker (lld).
On macOS, Apple's built-in clang does not support wasm32, so install Homebrew's LLVM and lld:
brew install llvm lld
On Linux, the distro clang should be fine. Install clang and lld packages.
Here's a basic C function (in fib.c):
int fib(int n) {
int a = 0, b = 1, c = 0;
for (int i = 1; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return a;
}make
The Makefile picks Homebrew's clang on macOS and the distro clang on Linux. You can also run the command directly:
clang fib.c -o fib.wasm \
--target=wasm32 -nostdlib -fvisibility=default -fuse-ld=lld \
-Xlinker --no-entry -Xlinker -export-dynamic
On macOS, replace clang with $(brew --prefix llvm)/bin/clang.
node node.js
Tip
bun node.js also works!
Serve over HTTP (needed for WebAssembly.instantiateStreaming):
python3 -m http.server 3000
Then open http://localhost:3000/
If you want to go beyond basic C, things get complicated fast which is why lots of tooling dedicated to this task exists. Good luck!
Tip
Surma has written a fantastic tutorial which goes much deeper into the stuff covered here.