Node.js · npm · tsc · ESLint · Prettier — in a tab

Run Node.js and your dev tools
in the browser.

NanoVM runs the real, unmodified Node.js v25 binary — plus npm, TypeScript, ESLint and Prettier — entirely client-side. No server, no container, no install. An open-source alternative to WebContainers.

real Node v25.4.0·585 KB core·100% client-side·open source
Not a reimplementation

Other in-browser runtimes ship a reimplemented Node. NanoVM runs the actual Node.js executable — the same binary you’d install on a Linux server — instruction by instruction on an emulated RISC-V CPU. If it works on Node, it works here: the same APIs, the same versions, the same edge cases.

The toolchain

Your everyday dev tools, unmodified.

Node.js
v25.4.0
The real upstream runtime — require, fs, crypto, http, streams, Buffer, EventEmitter and async/await.
npm
v11.7.0
Install and run packages; dependencies are pulled over HTTPS through the host-fetch bridge.
TypeScript
v5.9.3
tsc type-checks and compiles your project, completely unmodified, inside the VM.
ESLint
v10.0.0
Lint real codebases with the actual ESLint binary and your own configuration.
Prettier
v3.8.1
Format files with the real Prettier — byte-for-byte the same output as your terminal.
BusyBox + catalog
fd · ripgrep · …
Coreutils out of the box, plus extra Linux tools installed on demand from the signed catalog.
How it works

Four lines, from boot to output.

01
Boot the VM
createNano() loads the ~585 KB nano.wasm and the Node binary. No server, no container — just static assets on a CDN.
02
Write your files
Seed the in-memory filesystem with your sources via nano.fs.writeFile — synchronously, with no round-trips.
03
Run the toolchain
nano.shExec("npx tsc && node dist/main.js") or nano.node([…]) runs the real binaries and streams stdout as it appears.
04
Serve & preview
Run an HTTP server inside the VM and render it in a live iframe through the service-worker bridge.
In code

Boot, write, run.

javascript
import { createNano, nanoImage } from "@userland-run/nano-sdk";

// boot the VM — real Node + the npm toolchain, 100% in the browser
const nano = await createNano({
  image: nanoImage({ baseUrl: "/nano/", withNode: true, withDevenv: true }),
});

// write a TypeScript file into the in-memory filesystem
nano.fs.writeFile(
  "/app/main.ts",
  'const who: string = "RISC-V";\nconsole.log(`hello from ${who}`);',
);

// type-check + run it with the real tsc and node binaries
const { stdout } = await nano.shExec("cd /app && npx tsc main.ts && node main.js");
console.log(stdout); // hello from RISC-V

Need a tight run loop? Snapshot V8 once and restore it per run with the Node fast path.

javascript
// snapshot V8 once, then restore it per run for a fast loop
const rt = nano.nodeRuntime();
await rt.warmup();
await rt.run("console.log(process.version)"); // → v25.4.0
userland.run vs WebContainers

An honest head-to-head.

userland.run
WebContainers
Cloud sandbox
Node.js engine
real Node binary
custom Node reimpl.
real Node (remote)
Runs fully client-side
yes
yes
no — server
Core download
585 KB
several MB
Other Linux tools
yes — fd, ripgrep…
limited
yes
Open source
AGPL / MPL
proprietary
varies
Cross-origin isolation
required
required
n/a
Execution speed
emulated — slower
near-native
native (remote)
WebContainers is a trademark of StackBlitz. Comparison reflects public behavior at the time of writing.
The honest trade-offs
NanoVM emulates RISC-V, so heavy compute runs slower than a native or near-native runtime — it’s excellent for editors, linters, type-checks, scripts and demos, and is not a production compute engine. Networking is brokered through the host’s fetch() (HTTP/HTTPS only, subject to CORS), so there are no raw TCP sockets yet. And, like any shared-memory tool, the page must be cross-origin isolated (COOP/COEP) — the SDK ships a service worker that arranges this for you.

Put real Node in your app.

The SDK is a typed, ESM, zero-dependency package. Install it, point it at the wasm, and you have a Linux dev environment running in your users’ browsers.