userland.rundocs70Try the demo
Internals

Architecture

NanoVM is a shared kernel (bus, virtual filesystem, process router, networking, capabilities, services) with four peer runners that each execute one kind of program on a different engine, plus apps delivered through a signed catalog.

text
                        ┌──────────────────────────────┐
                        │            kernel/            │
                        │  bus · VFS · router · net ·   │
                        │  caps · services · platform   │
                        └──────────────┬───────────────┘
              register delegates via   │ router (runners never import each other)
        ┌───────────────┬──────────────┼───────────────┐
        ▼               ▼              ▼               ▼
   runners/riscv    runners/node   runners/wasm    runners/boa
   RV64 ELF emu     Node.js on     wasm32-wasip1   sandboxed JS
   (Rust→wasm)      host JS        commands        (Boa, Rust→wasm)
        ▲
        │ apps (ripgrep, node, …) target a runner ABI, delivered via the catalog

The kernel

Part
Role
bus
typed messages between the page, runners and services (SharedArrayBuffer and MessagePort channels)
VFS
the shared in-memory POSIX filesystem (kernel/vfs/memfs.mjs) every runner reads and writes
proc / router
process table, pipes, signals, and the router that dispatches a spawn to a runner's delegate
net
the port table for listeners and the outbound fetch bridge (/dev/__net__)
caps
capability profiles that scope what a process may touch
services
shared services reachable over the bus (zlib, duckdb, type-strip, …); which ones are registered depends on the host setup
platform
worker spawning and module-URL resolution for browser and Node.js hosts

The runners

Runner
Runs
Engine
Trust
Speed
riscv
RV64 ELF (BusyBox, Node.js)
emulated CPU (Rust → wasm)
fidelity reference
slow
node
Node.js programs
host JS engine ("nodert")
trusted
fast
wasm
wasm32-wasip1 commands
host wasm engine
capability-scoped
fast
boa
untrusted JS
Boa interpreter (Rust → wasm)
sandboxed
medium

The RISC-V runner is the original NanoVM and the oracle the faster runners are tested against: differential tests run the same program on nodert and on the real Node.js ELF in the VM and fail on any difference not recorded in the divergence registry (runners/node/DIVERGENCES.md; see Limitations).

The dependency rule

  • A runner imports only from kernel/ (plus kernel/platform.mjs for host infrastructure).
  • No runner imports another runner. Cross-runner work goes through router.route(), the bus and the shared VFS.
  • Apps target a runner ABI (riscv64gc-linux-musl, wasm32-wasip1) and import nothing; the catalog delivers them.
  • Known exception: runners/riscv/host/nanovm.mjs lazily imports runners/boa/host/boa.mjs for scripting.
SDK · JavaScript

Three runners, one filesystem

Node.js (host engine) writes a file, BusyBox (RISC-V) transforms it, and a wasm app reads the image next to it, all through the shared VFS.

javascript
await nano.node(["-e", "require('fs').writeFileSync('/work/msg.txt', 'written by node\\n')"]);
await nano.shExec("tr a-z A-Z < /work/msg.txt > /work/MSG.txt");
print(nano.fs.readText("/work/MSG.txt").trim());
await nano.registerWasmApp("photon", new Uint8Array(await (await fetch("/nano/photon.wasm")).arrayBuffer()));
nano.fs.writeFile("/work/in.jpg", new Uint8Array(await (await fetch("/demo-files/photon/sample.jpg")).arrayBuffer()));
print((await nano.execWasmApp(["photon", "in.jpg", "out.png", "--filter", "grayscale"], { cwd: "/work" })).stdout.trim());
print((await nano.shExec("ls /work | tr '\\n' ' '")).stdout.trim());
loading…
Expected output
WRITTEN BY NODE
photon: grayscale 360x240 -> out.png (360x240 PNG)
MSG.txt in.jpg msg.txt out.png

The SDK on top

@userland-run/nano-sdk vendors the kernel and runners and adds the typed API: createNano, the Shell, serve mode, the worker transport, the catalog client and provision(). The terminal UI (terminal repository) ships as the SDK's /terminal subpath.

Terminal: model and renderer

The terminal's model lives in the guest: term.rs (an ANSI/vte parser and a fixed cell grid) and tty.rs (line discipline and stdin ring) are compiled into nano.wasm. The <nano-terminal> element reads the grid out of linear memory and renders it with WebGPU or a 2D canvas. See Embedded terminal.

Product-level tours of each runner: RISC-V emulator, WASI apps, JS sandbox; and the cross-tier example.

Repositories

Repository
What
License
nano
kernel, runners, emulator, tests
AGPL-3.0-only OR LicenseRef-UEL
sdk
@userland-run/nano-sdk
MPL-2.0 OR LicenseRef-UEL
terminal
<nano-terminal> (re-exported by the SDK)
AGPL-3.0-only OR LicenseRef-UEL
catalog
recipes, signing tools, the CORS proxy
AGPL-3.0-only OR LicenseRef-UEL
website
this site and its docs
AGPL-3.0-only OR LicenseRef-UEL