Low-level SDK

Client

The browser-side API for creating and controlling an isolated Node.js runtime. Use it when you want full control over files, commands, processes, and previews.

$npm i @node-sandbox/client

Create a sandbox

Pass a public, origin-scoped API key and a project source to Sandbox.create(). Creation prepares the filesystem and installs dependencies, but does not start a web server.

sandbox.ts
import { Sandbox } from '@node-sandbox/client';

const sandbox = await Sandbox.create({
  apiKey: import.meta.env.VITE_NODESANDBOX_API_KEY,
  source: {
    type: 'git',
    url: 'https://github.com/vercel/sandbox-example-next.git',
  },
});
Safe for the browser.

API keys are intentionally public and only authorize exact origins configured in your dashboard.

Run commands

Use runCommand() for a program and argument list. It keeps arguments separate across the transport. Reach for runShell() only when you intentionally need shell syntax.

commands.ts
const version = await sandbox.runCommand('node', ['--version']);
console.log(version.stdout); // v22.14.0

const files = await sandbox.runShell('find src -name "*.tsx" | sort');
console.log(files.stdout);
runCommand(program, args)

Direct, safely separated arguments.

runShell(command)

Pipes, redirects, variables, and shell expansion.

runScript(name)

Run a finite package.json script.

commands.session()

Keep a working directory and environment between calls.

Long-running processes

Spawn a dev server, stream its output, and wait for the exact listener you expect. The process handle exits early if startup fails and can be terminated explicitly.

server.ts
const process = await sandbox.spawn('npm', ['run', 'dev']);

const stopListening = process.onOutput((chunk) => {
  console.log(chunk);
});

const preview = await sandbox.waitForPort(3000, { process });
console.log(preview.url, preview.port);

// Later:
stopListening();
process.kill('SIGTERM');

For the common case, start() spawns npm run dev and discovers the first HTTP listener. Pass { port: 3000 } when your application requires an exact port.

Project sources

Initialize from in-memory files, a ZIP archive, or a shallow Git checkout.

sources.ts
const files = await Sandbox.create({
  apiKey,
  source: { type: 'files', files: { 'index.js': 'console.log("hi")' } },
});

const zip = await Sandbox.create({
  apiKey,
  source: { type: 'zip', url: 'https://example.com/project.zip' },
});

const git = await Sandbox.create({
  apiKey,
  source: {
    type: 'git',
    url: 'https://github.com/org/repo.git',
    ref: 'main',
  },
});

const project = await Sandbox.create({
  apiKey,
  source: { type: 'project', projectId: 'project-id' },
});

Lifecycle

Provide a stable sessionId when a runtime needs to retain the same isolated origin. Always dispose the runtime when its owning screen or session ends.

lifecycle.ts
const sandbox = await Sandbox.create({
  apiKey,
  sessionId: 'project-preview-42',
  source: { type: 'files', files },
});

window.addEventListener('pagehide', () => sandbox.dispose(), { once: true });