NanoVM emulates an RV64GC RISC-V CPU in WebAssembly — enough Linux to run BusyBox, Node.js v25, and the full npm + TypeScript toolchain. No server. No install. Just a tab.
A single ~585 KB WebAssembly module emulates a 64-bit RISC-V CPU with roughly eighty Linux syscalls — enough memory management, file I/O, sockets, and threading to load real ELF binaries and run them unmodified. No transpilation, no shims. The actual BusyBox and Node.js binaries, executing instruction by instruction.
~/proj $ echo "Hello from RISC-V" | busybox cat Hello from RISC-V ~/proj $ busybox ls /usr/bin busybox node npm tsc eslint prettier ~/proj $ seq 5 | busybox sort -r 5 4 3 2 1
A monolithic exec() function whose dense dispatch compiles to a WASM br_table. #![no_std] Rust, fat-LTO'd into one function, talking to the host over just five imports.
Run the unmodified Node.js v25 binary — plus npm, TypeScript, ESLint and Prettier — entirely client-side. No server, no install, and it’s open source.
Run Node.js in the browser →@userland-run/nano-sdk is a typed, ESM, zero-dependency package: boot the VM, write files, run real binaries, host servers, and sandbox plugins. Code mode, a terminal engine, serve mode, scripting and a Web Worker transport — all from one import.
import { createNano, nanoImage } from "@userland-run/nano-sdk";
const nano = await createNano({
image: nanoImage({ baseUrl: "/nano/", withNode: true }),
});
nano.fs.writeFile("/app/data.txt", "3\n1\n2\n");
const { stdout } = await nano.shExec("sort -rn /app/data.txt | head -1");
console.log(stdout); // "3"# clone & build the ~585KB wasm module git clone https://github.com/userland-run/nano cd nano make build # run the suite — 24 passed, 0 failed make test # browser IDE: wasm + bundled binaries + vite make demo