Browser-native Node.js runtime. Run real Node.js code — filesystem, modules, require(), npm packages, HTTP servers — entirely inside the browser.
No backend. No containers. No WASM Node binary. Just polyfills, an in-memory filesystem, and a JavaScript execution engine.
Built by @R1ck404 — powering Scelar, the AI app builder that actually COMPLETELY builds your apps, from idea to production in a matter of minutes.
- Virtual Filesystem — Full in-memory
fsAPI (read, write, watch, streams, symlinks, glob) - Module System —
require(),import,module.exports,package.jsonresolution, conditional exports - npm Packages — Install real packages from the npm registry, extracted and resolved in-browser
- HTTP Servers — Run Express, Hono, Elysia, vite and other frameworks with real request/response routing
- Shell — Built-in bash-like shell with 35+ commands (ls, cat, grep, find, sed, etc.), pipes, redirections, variable expansion
- Process Model — Web Worker-based processes with
child_process.exec/spawn/fork,worker_threads, and IPC - Terminal — Drop-in xterm.js integration with line editing, history, raw mode, Ctrl+C
- Preview — Service Worker-based iframe preview with script injection and WebSocket bridging
- Snapshots — Save and restore the entire filesystem state
npm install @scelar/nodepodimport { Nodepod } from '@scelar/nodepod';
// Boot a nodepod instance with some files
const nodepod = await Nodepod.boot({
files: {
'/index.js': 'console.log("Hello from the browser!")',
},
});
// Run a script
const proc = await nodepod.spawn('node', ['index.js']);
proc.on('output', (text) => console.log(text));
await proc.completion;
// Read/write files
await nodepod.fs.writeFile('/data.json', JSON.stringify({ hello: 'world' }));
const content = await nodepod.fs.readFile('/data.json', 'utf8');nodepod provides built-in xterm.js terminal support:
import { Nodepod } from '@scelar/nodepod';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
const nodepod = await Nodepod.boot();
const terminal = nodepod.createTerminal({ Terminal, FitAddon });
terminal.attach('#terminal-container');The terminal handles line editing, command history, prompt rendering, raw/cooked mode, and streaming output out of the box.
const nodepod = await Nodepod.boot({
files: {
'/server.js': `
const express = require('express');
const app = express();
app.get('/', (req, res) => res.json({ status: 'ok' }));
app.listen(3000, () => console.log('Server running on port 3000'));
`,
},
});
// Install express
await nodepod.install(['express']);
// Run the server
const proc = await nodepod.spawn('node', ['server.js']);
// Dispatch requests to the virtual server
const response = await nodepod.request(3000, 'GET', '/');
console.log(response.body); // { status: 'ok' }Inject scripts into preview iframes before any page content loads — useful for setting up bridges between the main window and the iframe:
await nodepod.setPreviewScript(`
window.__bridge = {
sendToParent(msg) { window.parent.postMessage(msg, '*'); }
};
`);
// Remove it later
await nodepod.clearPreviewScript();Creates a fully wired nodepod instance.
| Option | Type | Default | Description |
|---|---|---|---|
files |
Record<string, string> |
— | Initial files to populate the filesystem |
workdir |
string |
"/" |
Working directory |
env |
Record<string, string> |
— | Environment variables |
swUrl |
string |
— | Service Worker URL (enables preview iframes) |
watermark |
boolean |
true |
Show a small "nodepod" badge in preview iframes |
onServerReady |
(port, url) => void |
— | Callback when a virtual server starts listening |
allowedFetchDomains |
string[] | null |
npm/github defaults | Extra domains allowed through the CORS proxy. Pass null to allow all |
| Method | Description |
|---|---|
spawn(cmd, args?) |
Run a command, returns NodepodProcess |
createTerminal(opts) |
Create an interactive terminal |
install(packages) |
Install npm packages |
fs.readFile(path, enc?) |
Read a file |
fs.writeFile(path, data) |
Write a file |
fs.readdir(path) |
List directory contents |
fs.stat(path) |
Get file stats |
fs.mkdir(path, opts?) |
Create a directory |
fs.rm(path, opts?) |
Remove files/directories |
snapshot() |
Capture filesystem state |
restore(snapshot) |
Restore filesystem from snapshot |
setPreviewScript(script) |
Inject JS into preview iframes |
clearPreviewScript() |
Remove injected preview script |
port(num) |
Get preview URL for a virtual server port |
Returned by spawn(). An EventEmitter with:
| Event | Payload | Description |
|---|---|---|
output |
string |
stdout data |
error |
string |
stderr data |
exit |
number |
exit code |
Property: completion — a Promise<void> that resolves when the process exits.
nodepod includes several security measures for running untrusted code:
- CORS proxy domain whitelist — Proxied fetch requests only go through to whitelisted domains (npm registry, GitHub, esm.sh, etc by default). Extend via the
allowedFetchDomainsboot option or passnullto disable - Service Worker auth — Control messages to the SW require a random token generated at boot, so other scripts on the same origin can't inject preview content
- WebSocket bridge auth — The BroadcastChannel used for WS bridging between preview iframes and the main thread is token-authenticated
- Package integrity — Downloaded npm tarballs are checked against the registry's
shasumbefore extraction - Iframe sandbox — The cross-origin iframe mode uses
sandbox="allow-scripts"to prevent top-frame navigation, popups, and form submissions - Origin-checked messaging — The sandbox page validates
event.originon incoming messages and only responds to the configured parent origin
nodepod
├── src/
│ ├── script-engine.ts # JavaScript execution engine (require, ESM→CJS, REPL)
│ ├── memory-volume.ts # In-memory virtual filesystem
│ ├── syntax-transforms.ts # ESM-to-CJS conversion via acorn
│ ├── module-transformer.ts # esbuild-wasm code transforms
│ ├── polyfills/ # Node.js built-in module polyfills
│ │ ├── fs.ts # Filesystem (read, write, watch, streams, glob)
│ │ ├── http.ts # HTTP server/client
│ │ ├── stream.ts # Readable, Writable, Transform, Duplex
│ │ ├── events.ts # EventEmitter
│ │ ├── path.ts # Path operations
│ │ ├── crypto.ts # Hashing, randomBytes, randomUUID
│ │ ├── child_process.ts # exec, spawn, fork, execSync
│ │ ├── net.ts # TCP Socket, Server
│ │ └── ... # 40+ more polyfills
│ ├── shell/ # Bash-like shell interpreter
│ │ ├── shell-parser.ts # Tokenizer + recursive-descent parser
│ │ ├── shell-builtins.ts # 35+ built-in commands
│ │ └── shell-interpreter.ts # AST executor, pipes, redirections
│ ├── packages/ # npm package management
│ │ ├── installer.ts # Package installer
│ │ ├── registry-client.ts # npm registry client
│ │ └── version-resolver.ts # Semver resolution
│ ├── threading/ # Worker-based process model
│ │ ├── process-manager.ts # Process lifecycle management
│ │ └── process-handle.ts # Process I/O handle
│ └── sdk/ # Public SDK layer
│ ├── nodepod.ts # Nodepod.boot() entry point
│ ├── nodepod-fs.ts # Async filesystem facade
│ ├── nodepod-process.ts # Process handle
│ └── nodepod-terminal.ts # xterm.js terminal integration
└── static/
└── __sw__.js # Service Worker for HTTP request interception
Full implementations: fs, path, events, stream, buffer, process, http, https, net, crypto, zlib, url, querystring, util, os, tty, child_process, assert, readline, module, timers, string_decoder, perf_hooks, constants, punycode
Shims/stubs: dns, worker_threads, vm, v8, tls, dgram, cluster, http2, inspector, domain, diagnostics_channel, async_hooks
Once published to npm, nodepod is automatically available on CDNs:
<!-- unpkg -->
<script src="https://unpkg.com/@scelar/nodepod"></script>
<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/@scelar/nodepod"></script>git clone https://github.com/ScelarOrg/Nodepod.git
cd Nodepod
npm install
npm run type-check # TypeScript validation
npm run build:lib # Build ESM + CJS bundles
npm test # Run testsSee CONTRIBUTING.md for setup instructions and guidelines.
Created by @R1ck404. Part of the Scelar ecosystem.
This project uses the MIT license with the Commons Clause restriction. In plain terms:
- Use it freely in your own projects, including commercial ones
- Modify it, fork it, learn from it
- Ship products built with nodepod — that's totally fine
- Don't resell nodepod itself as a standalone product or hosted service
Basically, build whatever you want with it — just don't take nodepod, rebrand it, and sell it as your own thing.