@aistack/sandbox
v1.0.0
Published
Drop-in replacement for @vercel/sandbox - run AI sandboxes on your own infrastructure
Maintainers
Readme
@aistack/sandbox
A drop-in replacement for sandbox by vercel that runs on your own infrastructure using Docker and Tailscale.
Why?
- 100% API Compatible with
@vercel/sandbox- just change the import - Self-hosted - run on your own servers with full control
- Multiple Runtimes - Bun, Node.js 22/24, Python 3.10
- Tailscale Integration - secure networking with optional public URLs via Funnel
- No vendor lock-in - migrate to/from Vercel Sandbox with one line change
Installation
npm install @aistack/sandbox
# or
yarn add @aistack/sandbox
# or
pnpm add @aistack/sandbox
# or
bun add @aistack/sandboxQuick Start
Migrating from Vercel Sandbox
// Before (Vercel)
import { Sandbox } from '@vercel/sandbox';
// After (AIStack) - just change the import and set your endpoint!
import { Sandbox } from '@aistack/sandbox';
Sandbox.setEndpoint('http://your-server:3456');
Sandbox.setApiSecret('your-api-secret');
// Everything else stays exactly the same!
const sandbox = await Sandbox.create({
runtime: 'bun',
resources: { vcpus: 2 },
timeout: 5 * 60 * 1000,
});Full Example
import { Sandbox } from '@aistack/sandbox';
// Configure once
Sandbox.setEndpoint(process.env.SANDBOX_ENDPOINT || 'http://localhost:3456');
Sandbox.setApiSecret(process.env.SANDBOX_API_SECRET);
async function main() {
// Create a sandbox
const sandbox = await Sandbox.create({
runtime: 'bun', // 'bun' | 'node22' | 'node24' | 'nvm22' | 'python3.10'
resources: { vcpus: 2 },
timeout: 10 * 60 * 1000,
ports: [3000],
});
console.log(`Sandbox created: ${sandbox.sandboxId}`);
// Run commands
const result = await sandbox.runCommand('node', ['--version']);
console.log(`Node version: ${result.stdout}`);
// Run with streaming output
await sandbox.runCommand({
cmd: 'npm',
args: ['install'],
stdout: process.stdout,
stderr: process.stderr,
});
// Write files
await sandbox.writeFiles([{ path: 'index.js', content: Buffer.from('console.log("Hello!")') }]);
// Read files
const stream = await sandbox.readFile({ path: 'package.json' });
// Run detached (background) processes
const server = await sandbox.runCommand({
cmd: 'npm',
args: ['start'],
detached: true,
});
console.log(`Server PID: ${server.pid}`);
// Get internal URL (Tailscale network)
const internalUrl = sandbox.domain(3000);
// Get public URL (via Tailscale Funnel)
const publicUrl = await sandbox.getPublicUrl(3000);
// Cleanup
await sandbox.stop();
}
main();API Reference
Static Methods
Sandbox.setEndpoint(url: string)
Set the control plane URL.
Sandbox.setApiSecret(secret: string)
Set the API authentication secret.
Sandbox.create(options): Promise<Sandbox>
Create a new sandbox.
const sandbox = await Sandbox.create({
runtime?: 'bun' | 'node22' | 'node24' | 'nvm22' | 'python3.10', // default: 'bun'
resources?: { vcpus?: number }, // default: { vcpus: 2 }
timeout?: number, // milliseconds, default: 5 minutes
ports?: number[], // ports to expose
source?: { // optional: clone a git repo
url: string,
type: 'git',
branch?: string,
token?: string, // for private repos
},
});Sandbox.get(sandboxId: string): Promise<Sandbox>
Get an existing sandbox by ID.
Sandbox.list(options?): Promise<{ sandboxes, pagination }>
List all sandboxes.
Instance Methods
sandbox.runCommand(cmd, args?, opts?): Promise<CommandFinished>
Run a command and wait for completion.
// Simple form
const result = await sandbox.runCommand('ls', ['-la']);
console.log(result.stdout);
console.log(result.exitCode);
// With options
const result = await sandbox.runCommand({
cmd: 'npm',
args: ['install'],
cwd: '/app',
env: { NODE_ENV: 'production' },
sudo: false,
stdout: process.stdout, // stream output
stderr: process.stderr,
});sandbox.runCommand({ ...opts, detached: true }): Promise<Command>
Run a command in the background.
const cmd = await sandbox.runCommand({
cmd: 'npm',
args: ['start'],
detached: true,
});
console.log(`PID: ${cmd.pid}`);
await cmd.kill(); // stop it latersandbox.writeFiles(files): Promise<void>
Write files to the sandbox.
await sandbox.writeFiles([
{ path: 'app.js', content: Buffer.from('console.log("Hi")') },
{ path: 'config.json', content: Buffer.from('{"debug": true}') },
]);sandbox.readFile(file): Promise<ReadableStream | null>
Read a file from the sandbox.
const stream = await sandbox.readFile({ path: 'output.txt' });
if (stream) {
const reader = stream.getReader();
const { value } = await reader.read();
console.log(Buffer.from(value).toString());
}sandbox.mkDir(path): Promise<void>
Create a directory.
sandbox.domain(port): string
Get the internal Tailscale URL for a port.
const url = sandbox.domain(3000);
// Returns: http://100.x.y.z:3000sandbox.getPublicUrl(port): Promise<string>
Get a public URL via Tailscale Funnel.
const publicUrl = await sandbox.getPublicUrl(3000);
// Returns: https://sandbox-abc123.your-tailnet.ts.netsandbox.stop(): Promise<void>
Stop and remove the sandbox.
sandbox.extendTimeout(ms): Promise<void>
Extend the sandbox timeout.
Properties
sandbox.sandboxId- Unique sandbox identifiersandbox.status- Current status:'pending' | 'running' | 'stopping' | 'stopped' | 'failed'sandbox.timeout- Timeout in milliseconds
Environment Variables
| Variable | Description |
| -------------------- | -------------------------------------------------- |
| SANDBOX_ENDPOINT | Control plane URL (alternative to setEndpoint()) |
| SANDBOX_API_SECRET | API secret (alternative to setApiSecret()) |
| API_SECRET | Fallback for API secret |
Available Runtimes
| Runtime | Description |
| --------------- | --------------------------------------- |
| bun (default) | Bun (latest) + Node.js 22 + Python 3.10 |
| node22 | Node.js 22 LTS + Python 3.10 |
| node24 | Node.js 24 + Python 3.10 |
| nvm22 | NVM with Node 22 + Python 3.10 |
| python3.10 | Python 3.10 only |
Self-Hosting
This SDK requires a self-hosted control plane. See the full documentation for setup instructions.
Quick Setup
git clone https://github.com/aistack/sandbox.git
cd sandbox
bun install
bun run docker:build
bun run startComparison with Vercel Sandbox
| Feature | Vercel Sandbox | @aistack/sandbox | | ----------- | -------------- | ----------------------- | | API | ✅ | ✅ 100% compatible | | Self-hosted | ❌ | ✅ | | Runtimes | Bun, Node | Bun, Node 22/24, Python | | Networking | Vercel domain | Tailscale + Funnel | | Cost | Per-usage | Your infrastructure | | Max timeout | 5 hours (Pro) | Configurable |
License
MIT
