Migration Guide
Concept mapping
Section titled “Concept mapping”| Concept | WebContainers | Nodebox | bolo |
|---|---|---|---|
| Boot | WebContainer.boot() | new Nodebox({ iframe }); .connect() | boot() |
| Mount files | .mount(files) | fs.init(fileMap) | vfs.writeFile(path, content) per file, or vfs.restore(snapshot) for bulk |
| Run command | .spawn('node', ['file.js']) | shell.runCommand('node', ['file.js']) | shell.execute('runtime run file.js') |
| Streaming output | process.output.pipeTo(writable) | shell output stream | execute(cmd, { stdout, stderr }) callbacks |
| npm install | .spawn('npm', ['install']) | shell.runCommand('npm', ['install']) | shell.execute('npm install') |
| Preview URL | .on('server-ready', handler) | port forwarding | SWSandbox virtual origin via iframe |
| Untrusted sandbox | — | — | shell.execute('agent run file.js') (QuickJS tier) |
| Trusted user code | Native (full Node.js) | Native (polyfills) | shell.execute('runtime run file.js') (V8 Web Worker) |
Coming from WebContainers
Section titled “Coming from WebContainers”Before (WebContainers)
Section titled “Before (WebContainers)”import { WebContainer } from '@webcontainer/api';
const container = await WebContainer.boot();
await container.mount({ 'index.js': { file: { contents: 'console.log("hello")' } }});
const proc = await container.spawn('node', ['index.js']);proc.output.pipeTo(new WritableStream({ write: (chunk) => console.log(chunk) }));await proc.exit;After (bolo)
Section titled “After (bolo)”import { boot } from '@bolojs/runtime';
const container = await boot();
await container.mount({ 'index.js': { file: { contents: 'console.log("hello")' } },});
const proc = container.spawn('node', ['index.js']);proc.output.pipeTo(new WritableStream({ write: (chunk) => console.log(chunk) }));await proc.exit;Key differences:
boot()mirrors@webcontainer/api’s shape directly — samemount()/spawn()/fs/on('server-ready')/teardown()surfacespawn()’soutputis aReadableStream<string>(not bytes);container.fsexposesreadFile/writeFile/mkdir/rm/readdir/rename/watch(fs.promises-style, nostat/lstat/symlinks in v1.0)- The lower-level primitives (
VfsBus,SWSandbox,ShellService,RuntimeWorker,SandboxPool) are still available directly for callers who want manual wiring instead ofboot()
Coming from Nodebox
Section titled “Coming from Nodebox”Before (Nodebox)
Section titled “Before (Nodebox)”import { Nodebox } from '@codesandbox/nodebox';
const sandbox = new Nodebox({ iframe: document.getElementById('preview') });await sandbox.connect();
await sandbox.fs.init({ 'index.js': 'console.log("hello")',});
const shell = await sandbox.shell.create();const { stdout } = await shell.runCommand('node', ['index.js']);console.log(stdout);After (bolo)
Section titled “After (bolo)”// (same boot sequence as above)
// Bulk mount via snapshotvfs.restore({ '/index.js': 'console.log("hello")',});
// Runconst result = await shell.execute('runtime run /index.js', { stdout: (chunk) => process.stdout.write(chunk),});Key differences:
fs.init(fileMap)→vfs.restore(snapshot)for bulk mount, or multiplevfs.writeFilecallsshell.runCommand('node', ['file.js'])→shell.execute('runtime run file.js')npm,runtime, andagentare special-cased to wire into the container’s package manager/runtime worker/sandbox pool; every other command line runs through a real bash interpreter (just-bash) backed byVfsBus, with full support for pipes, redirection, quoting, and POSIX builtins (ls,cat,mkdir,rm,cp,mv,grep,sed, etc.)
No equivalent yet
Section titled “No equivalent yet”These features exist in WebContainers or Nodebox but are not yet implemented:
| Feature | Status |
|---|---|
| npm-published packages | Roadmap |
| Full Node.js native package support (NAPI) | Not planned (WASM/JS only) |
fork() / cluster | Not planned |