Menu

Sandbox SDK Reference

Last updated January 15, 2026

Vercel Sandbox is available in Beta on all plans

The Vercel Sandbox Software Development Kit (SDK) lets you create ephemeral Linux microVMs on demand. Use it to evaluate user-generated code, run AI agent output safely, test services without touching production resources, or run reproducible integration tests that need a full Linux environment with sudo access.

Install the SDK:

Terminal
pnpm i @vercel/sandbox

After installation:

  • Link your project and pull environment variables with vercel link and vercel env pull so the SDK can read a Vercel OpenID Connect (OIDC) token.
  • Choose a runtime: node24, node22, or python3.13.
ClassWhat it doesExample
SandboxCreates and manages isolated microVM environmentsconst sandbox = await Sandbox.create()
CommandHandles running commands inside the sandboxconst cmd = await sandbox.runCommand()
CommandFinishedContains the result after a command completesAccess cmd.exitCode and cmd.stdout()
// 1. Create a sandbox
const sandbox = await Sandbox.create({ runtime: 'node24' });
 
// 2. Run a command - it waits for completion and returns the result
const result = await sandbox.runCommand('node', ['--version']);
 
// 3. Check the result
console.log(result.exitCode); // 0
console.log(await result.stdout()); // v22.x.x

The Sandbox class gives you full control over isolated Linux microVMs. Use it to create new sandboxes, inspect active ones, stream command output, and shut everything down once your workflow is complete.

Use sandboxId to identify the current microVM so you can reconnect to it later with Sandbox.get() or trace command history. Store this ID whenever your workflow spans multiple processes or retries so you can resume log streaming after a restart.

Returns: string.

console.log(sandbox.sandboxId);

The status accessor reports the lifecycle state of the sandbox so you can decide when to queue new work or perform cleanup. Poll this value when you need to wait for startup or confirm shutdown, and treat failed as a signal to create a new sandbox.

Returns: "pending" | "running" | "stopping" | "stopped" | "failed".

console.log(sandbox.status);

timeout shows how many milliseconds remain before the sandbox stops automatically. Compare the remaining time against upcoming commands and call sandbox.extendTimeout() if the window is too short.

Returns: number.

console.log(sandbox.timeout);

The createdAt accessor returns the date and time when the sandbox was created. Use this to track sandbox age or calculate how long a sandbox has been running.

Returns: Date.

console.log(sandbox.createdAt);

Use Sandbox.list() to enumerate sandboxes for a project, optionally filtering by time range or page size. Combine since and until with the pagination cursor and cache the last pagination.next value so you can resume after restarts without missing entries.

Returns: Promise<Parsed<{ sandboxes: SandboxSummary[]; pagination: Pagination; }>>.

ParameterTypeRequiredDetails
projectIdstringYesProject whose sandboxes you want to list.
limitnumberNoMaximum number of sandboxes to return.
sincenumber | DateNoList sandboxes created after this time.
untilnumber | DateNoList sandboxes created before this time.
signalAbortSignalNoCancel the request if necessary.
const { sandboxes } = await Sandbox.list({ projectId });

Sandbox.create() launches a new microVM with your chosen runtime, source, and resource settings. Defaults to an empty workspace when no source is provided. Pass source.depth when cloning large repositories to shorten setup time.

Returns: Promise<Sandbox>.

ParameterTypeRequiredDetails / Values
sourcegitNoClone a Git repository.
url: string
username: string
password: string
depth?: number
revision?: string
sourcetarballNoMount a tarball.
url: string
resources.vcpusnumberNoOverride CPU count (defaults to plan baseline).
runtimestringNoRuntime image such as "node24", "node22", or "python3.13".
portsnumber[]NoPorts to expose for sandbox.domain().
timeoutnumberNoInitial timeout in milliseconds.
signalAbortSignalNoCancel sandbox creation if needed.
const sandbox = await Sandbox.create({ runtime: 'node24' });

Sandbox.get() rehydrates an active sandbox by ID so you can resume work or inspect logs. It throws if the sandbox no longer exists, so cache sandboxId only while the job is active and clear it once the sandbox stops.

Returns: Promise<Sandbox>.

ParameterTypeRequiredDetails
sandboxIdstringYesIdentifier of the sandbox to retrieve.
signalAbortSignalNoCancel the request if necessary.
const sandbox = await Sandbox.get({ sandboxId });

Call sandbox.getCommand() to retrieve a previously executed command by its ID, which is especially helpful after detached executions when you want to inspect logs later.

Returns: Promise<Command>.

ParameterTypeRequiredDetails
cmdIdstringYesIdentifier of the command to fetch.
opts.signalAbortSignalNoCancel the lookup if it takes too long.
const command = await sandbox.getCommand(cmdId);

sandbox.runCommand() executes commands inside the microVM, either blocking until completion or returning immediately in detached mode. Use detached: true for long-running servers, stream output to local log handlers, and call command.wait() later for results.

Returns: Promise<CommandFinished> when detached is falsy; Promise<Command> when detached is true.

ParameterTypeRequiredDetails
commandstringYesCommand to execute (string overload).
argsstring[]NoArguments for the string overload.
opts.signalAbortSignalNoCancel the command (string overload).
params.cmdstringYesCommand to execute when using the object overload.
params.argsstring[]NoArguments for the object overload.
params.cwdstringNoWorking directory for execution.
params.envRecord<string, string>NoAdditional environment variables.
params.sudobooleanNoRun the command with sudo.
params.detachedbooleanNoReturn immediately with a live Command object.
params.stdoutWritableNoStream standard output to a writable.
params.stderrWritableNoStream standard error to a writable.
params.signalAbortSignalNoCancel the command when using the object overload.
const result = await sandbox.runCommand('node', ['--version']);

sandbox.mkDir() creates directories in the sandbox filesystem before you write files or clone repositories. Paths are relative to /vercel/sandbox unless you provide an absolute path, so call this before writeFiles() when you need nested folders.

await sandbox.mkDir('tmp/assets');
ParameterTypeRequiredDetails
pathstringYesDirectory to create.
opts.signalAbortSignalNoCancel the operation.

Returns: Promise<void>.

Use sandbox.readFile() to pull file contents from the sandbox. The promise resolves to null when the file does not exist, so convert the returned stream to text or JSON before use.

const stream = await sandbox.readFile({ path: 'package.json' });
ParameterTypeRequiredDetails
file.pathstringYesPath to the file inside the sandbox.
file.cwdstringNoBase directory for resolving file.path.
opts.signalAbortSignalNoCancel the read operation.

Returns: Promise<null | ReadableStream>.

sandbox.writeFiles() uploads one or more files into the sandbox filesystem. Paths default to /vercel/sandbox; use absolute paths for custom locations and bundle related files into a single call to reduce round trips.

await sandbox.writeFiles([{ path: 'hello.txt', content: Buffer.from('hi') }]);
ParameterTypeRequiredDetails
files{ path: string; content: Buffer; }[]YesFile descriptors to write.
opts.signalAbortSignalNoCancel the write operation.

Returns: Promise<void>.

sandbox.domain() resolves a publicly accessible URL for a port you exposed during creation. It throws if the port is not registered to a route, so include the port in the ports array when creating the sandbox and cache the returned URL so you can share it quickly with collaborators.

const previewUrl = sandbox.domain(3000);
ParameterTypeRequiredDetails
pnumberYesPort number declared in ports.

Returns: string.

Call sandbox.stop() to terminate the microVM and free resources immediately. It's safe to call multiple times; subsequent calls resolve once the sandbox is already stopped, so invoke it as soon as you collect artifacts to control costs.

await sandbox.stop();
ParameterTypeRequiredDetails
opts.signalAbortSignalNoCancel the stop operation.

Returns: Promise<void>.

Use sandbox.extendTimeout() to extend the sandbox lifetime by the specified duration. This lets you keep the sandbox running up to the maximum execution timeout for your plan, so check sandbox.timeout first and extend only when necessary to avoid premature shutdown.

await sandbox.extendTimeout(60000); // Extend by 60 seconds
ParameterTypeRequiredDetails
durationnumberYesDuration in milliseconds to extend the timeout by.
opts.signalAbortSignalNoCancel the operation.

Returns: Promise<void>.

Command instances represent processes that run inside a sandbox. Detached executions created through sandbox.runCommand({ detached: true, ... }) return a Command immediately so that you can stream logs or stop the process later. Blocking executions that do not set detached still expose these methods through the CommandFinished object they resolve to.

The exitCode property holds the process exit status once the command finishes. For detached commands, this value starts as null and gets populated after you await command.wait(), so check for null to determine if the command is still running.

if (command.exitCode !== null) {
  console.log(`Command exited with code: ${command.exitCode}`);
}

Returns: number | null.

Use cmdId to identify the specific command execution so you can look it up later with sandbox.getCommand(). Store this value whenever you launch detached commands so you can replay output in dashboards or correlate logs across systems.

console.log(command.cmdId);

Returns: string.

The cwd accessor shows the working directory where the command is executing. Compare this value against expected paths when debugging file-related issues or verifying that relative paths resolve correctly.

console.log(command.cwd);

Returns: string.

startedAt returns the Unix timestamp (in milliseconds) when the command started executing. Subtract this from the current time to monitor execution duration or set timeout thresholds for long-running processes.

const duration = Date.now() - command.startedAt;
console.log(`Command has been running for ${duration}ms`);

Returns: number.

Call logs() to stream structured log entries in real time so you can watch command output as it happens. Each entry includes the stream type (stdout or stderr) and the data chunk, so you can route logs to different destinations or stop iteration when you detect a readiness signal.

for await (const log of command.logs()) {
  if (log.stream === 'stdout') {
    process.stdout.write(log.data);
  } else {
    process.stderr.write(log.data);
  }
}
ParameterTypeRequiredDetails
opts.signalAbortSignalNoCancel log streaming if needed.

Returns: AsyncGenerator<{ stream: "stdout" | "stderr"; data: string; }, void, void>.

Note: May throw StreamError if the sandbox stops while streaming logs.

Use wait() to block until a detached command finishes and get the resulting CommandFinished object with the populated exit code. This method is essential for detached commands where you need to know when execution completes. For non-detached commands, sandbox.runCommand() already waits automatically.

const detachedCmd = await sandbox.runCommand({
  cmd: 'sleep',
  args: ['5'],
  detached: true,
});
const result = await detachedCmd.wait();
if (result.exitCode !== 0) {
  console.error('Something went wrong...');
}
ParameterTypeRequiredDetails
params.signalAbortSignalNoCancel waiting if you need to abort early.

Returns: Promise<CommandFinished>.

Use output() to retrieve stdout, stderr, or both as a single string. Choose "both" when you want combined output for logging, or specify "stdout" or "stderr" when you need to process them separately after the command finishes.

const combined = await command.output('both');
const stdoutOnly = await command.output('stdout');
ParameterTypeRequiredDetails
stream"stdout" | "stderr" | "both"YesThe output stream to read.
opts.signalAbortSignalNoCancel output streaming.

Returns: Promise<string>.

Note: This may throw string conversion errors if the command output contains invalid Unicode.

stdout() collects the entire standard output stream as a string, which is handy when commands print JSON or other structured data that you need to parse after completion.

const output = await command.stdout();
const data = JSON.parse(output);
ParameterTypeRequiredDetails
opts.signalAbortSignalNoCancel the read while the command runs.

Returns: Promise<string>.

Note: This may throw string conversion errors if the command output contains invalid Unicode.

stderr() gathers all error output produced by the command. Combine this with exitCode to build user-friendly error messages or forward failure logs to your monitoring system.

const errors = await command.stderr();
if (errors) {
  console.error('Command errors:', errors);
}
ParameterTypeRequiredDetails
opts.signalAbortSignalNoCancel the read while collecting error output.

Returns: Promise<string>.

Note: This may throw string conversion errors if the command output contains invalid Unicode.

Call kill() to terminate a running command using the specified signal. This lets you stop long-running processes without destroying the entire sandbox. Send SIGTERM by default for graceful shutdown, or use SIGKILL for immediate termination.

await command.kill('SIGKILL');
ParameterTypeRequiredDetails
signalSignalNoThe signal to send to the process. Defaults to SIGTERM.
opts.abortSignalAbortSignalNoCancel the kill operation.

Returns: Promise<void>.

CommandFinished is the result you receive after a sandbox command exits. It extends the Command class, so you keep access to streaming helpers such as logs() or stdout(), but you also get the final exit metadata immediately. You usually receive this object from sandbox.runCommand() or by awaiting command.wait() on a detached process.

The exitCode property reports the numeric status returned by the command. A value of 0 indicates success; any other value means the process exited with an error, so branch on it before you parse output.

if (result.exitCode === 0) {
  console.log('Command succeeded');
}

Returns: number.

Use cmdId to identify the specific command execution so you can reference it in logs or retrieve it later with sandbox.getCommand(). Store this ID whenever you need to trace command history or correlate output across retries.

console.log(result.cmdId);

Returns: string.

The cwd accessor shows the working directory where the command executed. Compare this value against expected paths when debugging file-related failures or relative path issues.

console.log(result.cwd);

Returns: string.

startedAt returns the Unix timestamp (in milliseconds) when the command started executing. Subtract this from the current time or from another timestamp to measure execution duration or schedule follow-up tasks.

const duration = Date.now() - result.startedAt;
console.log(`Command took ${duration}ms`);

Returns: number.

CommandFinished inherits all methods from Command including logs(), output(), stdout(), stderr(), and kill(). See the Command class section for details on these methods.

The SDK prioritizes Vercel OIDC tokens that the CLI stores in .env.local. Link your project and pull environment variables with vercel link and vercel env pull.

Sandbox credentials expire. Rotate downloaded tokens at least every 12 hours during development.

For more background, read the authentication guide or the Vercel Sandbox authentication section.

  • Operating system: Amazon Linux 2023 with common build tools such as git, tar, openssl, and dnf.
  • Available runtimes: node24, node22, and python3.13 images with their respective package managers.
  • Resources: Choose the number of virtual CPUs (vcpus) per sandbox. Pricing and plan limits appear in the Sandbox pricing table.
  • Timeouts: The default timeout is 5 minutes. You can extend it programmatically up to 45 minutes on the Hobby plan and up to 5 hours on Pro and Enterprise plans.
  • Sudo: sudo commands run as vercel-sandbox with the root home directory set to /root.

The filesystem is ephemeral. You must export artifacts to durable storage if you need to keep them after the sandbox stops.


Was this helpful?

supported.