NodeOps
UK

Sandbox

Sandbox is a stateful handle that owns one sandbox id and exposes every per-sandbox operation: command execution, file transfer, lifecycle transitions, ingress, egress, bandwidth, networks, disks, and SSH. You receive a handle from client.createSandbox() or client.getSandbox(); you can also use static helpers Sandbox.create() and Sandbox.connect() to skip constructing a client explicitly.

Mutating calls (lifecycle, patch, resize, …) refresh the handle's cached projection in place. Read the projection back via the data getter or convenience getters (id, status, ip, name).

Every method that reaches the control plane also throws CreateosSandboxServerError on a 5xx response and CreateosSandboxConnectionError on network failure. Per-method Throws lists only conditions specific to that call.


At a glance

  • Package: @nodeops-createos/sandbox (npm)
  • Import: import { createClient } from "@nodeops-createos/sandbox"
  • Base URL: https://api.sb.createos.sh (override with CREATEOS_SANDBOX_BASE_URL)
  • Auth: API key via the apiKey option or CREATEOS_SANDBOX_API_KEY

Static factories

Sandbox.create

TypeScript
1static async create(
2 request: CreateSandboxRequest,
3 options?: CreateosSandboxClientOptions & CreateSandboxOptions,
4): Promise<Sandbox>

Creates a sandbox without constructing a client first. Equivalent to new CreateosSandboxClient(options).createSandbox(request, options).

Parameters

NameTypeDescription
requestCreateSandboxRequestShape, rootfs, and other create-time fields. See Types.
options?CreateosSandboxClientOptions & CreateSandboxOptionsClient config (API key, base URL, hooks) merged with create options (wait, waitTimeoutMs).

Returns Promise<Sandbox>

Throws

Example

TypeScript
1import { Sandbox } from "@nodeops-createos/sandbox";
2
3const sandbox = await Sandbox.create({ shape: "s-4vcpu-4gb", rootfs: "devbox:1" });
4try {
5 const out = await sandbox.runCommand("node", ["--version"]);
6 console.log(out.result.stdout);
7} finally {
8 await sandbox.destroy();
9}

Sandbox.connect

TypeScript
1static async connect(
2 id: string,
3 options?: CreateosSandboxClientOptions & RequestOptions,
4): Promise<Sandbox>

Connects to an existing sandbox by id without constructing a client first. Equivalent to new CreateosSandboxClient(options).getSandbox(id, options).

Parameters

NameTypeDescription
idstringSandbox id (e.g. "sb-01h…").
options?CreateosSandboxClientOptions & RequestOptionsClient config merged with per-request options.

Returns Promise<Sandbox>

Throws

Example

TypeScript
1import { Sandbox } from "@nodeops-createos/sandbox";
2
3const sandbox = await Sandbox.connect("sb-01h…");
4console.log(sandbox.status);

Properties

Getters over the handle's cached SandboxView projection. Call refresh() to re-sync from the server.

GetterTypeDescription
idstringSandbox id.
statusSandboxStatusCurrent lifecycle state: creating | running | pausing | paused | resuming | forking | error | destroying | destroyed | failed.
ipstring | undefinedVM private IP. undefined while the sandbox is still creating.
namestring | undefinedOptional user-supplied name.
dataSandboxViewThe full last-known projection. Returns the live internal object. Treat as read-only.
filesSandboxFilesFile transfer namespace. See Sandbox Files.

SandboxView additionally carries: vcpu, mem_mib, disk_mib, created_at, ingress_enabled, ingress_url_template?, running_at?, destroyed_at?, spawn_ms?, shape?, rootfs?, region?, egress?, envs?, ssh_pubkeys?, created_by?, bandwidth_ingress_bytes?, paused_at?, last_resumed_at?, forked_from?, auto_pause_after_seconds?.


Commands

runCommand

TypeScript
1async runCommand(
2 cmd: string,
3 args?: string[],
4 options?: ExecOptions,
5): Promise<ExecResponse>

Runs a command to completion and returns its buffered output. ExecOptions is an alias for RequestOptions: pass timeoutMs, signal, retry, or headers to control the request.

Parameters

NameTypeDescription
cmdstringExecutable name or absolute path.
args?string[]Argument list. Default [].
options?ExecOptionsPer-request options (timeout, signal, retry).

Returns Promise<ExecResponse>: { result: ExecResult; exec_ms: number } where ExecResult is { stdout, stderr, exit_code, error? }.

Throws

Example

TypeScript
1const { result } = await sandbox.runCommand("uname", ["-a"]);
2console.log(result.stdout, result.exit_code);

streamCommand

TypeScript
1async *streamCommand(
2 cmd: string,
3 args?: string[],
4 options?: ExecOptions,
5): AsyncGenerator<ExecStreamEvent>

Runs a command and yields discriminated union events that arrive over an NDJSON stream. Switch on event.type to handle each variant. Streaming requests are not retried.

Parameters

NameTypeDescription
cmdstringExecutable name or absolute path.
args?string[]Argument list. Default [].
options?ExecOptionsPer-request options.

Returns AsyncGenerator<ExecStreamEvent>

ExecStreamEvent union:

TypeScript
1| { type: "stdout"; data: string }
2| { type: "stderr"; data: string }
3| { type: "exit"; exitCode: number }
4| { type: "error"; message: string }
5| { type: "heartbeat" }

Throws: same as runCommand.

Example

TypeScript
1for await (const event of sandbox.streamCommand("tail", ["-f", "/var/log/syslog"])) {
2 switch (event.type) {
3 case "stdout": process.stdout.write(event.data); break;
4 case "stderr": process.stderr.write(event.data); break;
5 case "exit": console.log("exit code:", event.exitCode); break;
6 case "error": console.error("agent error:", event.message); break;
7 case "heartbeat": /* keepalive */ break;
8 }
9}

sh

TypeScript
1async sh(
2 script: string,
3 options?: ExecOptions & { label?: string },
4): Promise<ExecResponse>

Runs a shell script via bash -lc and throws on non-zero exit. Use this instead of runCommand when a failure should abort the caller without inspecting exit codes by hand.

Parameters

NameTypeDescription
scriptstringShell script. Pipes, redirection, globbing, and && chains work.
options.label?stringTag included in the thrown error message.
Other optionsExecOptionstimeoutMs, signal, retry, headers.

Returns Promise<ExecResponse>

Throws

Example

TypeScript
1await sandbox.sh("apt-get update -qq && apt-get install -y curl", {
2 label: "apt",
3 timeoutMs: 300_000,
4});
5const { result } = await sandbox.sh("curl -s https://api.ipify.org");
6console.log(result.stdout);

Files

File transfer operations live on the files accessor, which returns a SandboxFiles instance scoped to this sandbox.

TypeScript
1sandbox.files.upload("/path/in/sandbox", data);
2sandbox.files.download("/path/in/sandbox");

See Sandbox Files for full signatures.


Lifecycle

pause

TypeScript
1async pause(options?: RequestOptions): Promise<this>

Snapshots the sandbox to storage. The handle is updated to the pausing/paused projection. Combine with waitUntilPaused() to block until the snapshot completes.

Parameters: options?: RequestOptions (signal, headers, timeoutMs, retry).

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.pause();
2await sandbox.waitUntilPaused();

resume

TypeScript
1async resume(options?: RequestOptions): Promise<this>

Restores a paused sandbox. The handle is updated to the resuming/running projection. Combine with waitUntilRunning() to block until the VM is ready.

Parameters: options?: RequestOptions.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.resume();
2await sandbox.waitUntilRunning();

fork

TypeScript
1async fork(request?: ForkSandboxRequest, options?: RequestOptions): Promise<Sandbox>

Clones a paused sandbox into a new independent sandbox. Returns a handle to the clone.

Parameters

NameTypeDescription
request?ForkSandboxRequestFork overrides (see below).
options?RequestOptionsPer-request options.

ForkSandboxRequest fields (all optional):

FieldTypeDescription
start_paused?booleanKeep the fork paused instead of auto-resuming.
ssh_pubkeys?string[]Override authorized SSH keys on the clone.
egress?string[]Override egress allowlist on the clone.
ingress_enabled?booleanEnable/disable ingress on the clone.
envs?Record<string, string>Additional env vars for the clone.
bandwidth_quota_bytes?numberOverride bandwidth quota on the clone.

Returns Promise<Sandbox>: a handle to the new sandbox.

Throws

Example

TypeScript
1await sandbox.pause();
2await sandbox.waitUntilPaused();
3const clone = await sandbox.fork({ start_paused: false });
4console.log(clone.id);

destroy

TypeScript
1async destroy(options?: RequestOptions): Promise<DestroyedResponse>

Destroys the sandbox. The call returns when the row reaches destroying or destroyed; reclamation is async. Use waitUntilDestroyed() to block until fully reclaimed.

Parameters: options?: RequestOptions.

Returns Promise<DestroyedResponse>: { id: string; status: "destroying" | "destroyed" }.

Throws

Example

TypeScript
1await sandbox.destroy();
2await sandbox.waitUntilDestroyed();

resize

TypeScript
1async resize(diskMib: number, options?: RequestOptions): Promise<ResizeSandboxResponse>

Grows the overlay disk to diskMib. The value must exceed the current disk size. Shrinking is not supported.

Parameters

NameTypeDescription
diskMibnumberNew overlay disk size in MiB. Must be greater than the current size.
options?RequestOptionsPer-request options.

Returns Promise<ResizeSandboxResponse>: { id: string; disk_mib: number }.

Throws

Example

TypeScript
1await sandbox.resize(4096); // grow overlay to 4 GiB

setAutoPause

TypeScript
1async setAutoPause(seconds: number | null, options?: RequestOptions): Promise<this>

Sets or clears the idle auto-pause timeout. When set, the control plane pauses the sandbox after seconds of no detected activity. Pass null to disable. The handle is updated in place.

Parameters

NameTypeDescription
secondsnumber | nullIdle timeout in seconds (60-86400), or null to disable.
options?RequestOptionsPer-request options.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.setAutoPause(600); // pause after 10 min idle
2await sandbox.setAutoPause(null); // disable

waitUntilRunning

TypeScript
1async waitUntilRunning(options?: WaitOptions): Promise<this>

Polls until status === "running". Aborts early on terminal failure states including destroying/destroyed.

Parameters: options?: WaitOptions:

FieldTypeDescription
timeoutMs?numberWait budget in ms. Default 120000.
signal?AbortSignalCancels the wait.
request?RequestOptionsPer-poll request options (headers, retry, per-request timeout).

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.resume();
2await sandbox.waitUntilRunning({ timeoutMs: 60_000 });

waitUntilPaused

TypeScript
1async waitUntilPaused(options?: WaitOptions): Promise<this>

Polls until status === "paused". Aborts early on terminal failure states including destroying/destroyed.

Parameters: options?: WaitOptions.

Returns Promise<this>

Throws: same as waitUntilRunning.

Example

TypeScript
1await sandbox.pause();
2await sandbox.waitUntilPaused();

waitUntilDestroyed

TypeScript
1async waitUntilDestroyed(options?: WaitOptions): Promise<this>

Polls until status === "destroyed". destroying is treated as an intermediate step and does not abort the wait.

Parameters: options?: WaitOptions.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.destroy();
2await sandbox.waitUntilDestroyed();

Ingress & preview

setIngress

TypeScript
1async setIngress(enabled: boolean, options?: RequestOptions): Promise<this>

Enables or disables HTTP ingress. The handle is updated with the patched projection. After enabling, use previewUrl() to build the public URL.

Parameters

NameTypeDescription
enabledbooleantrue to enable, false to disable.
options?RequestOptionsPer-request options.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.setIngress(true);
2console.log(sandbox.previewUrl(8080));

waitForPortReady

TypeScript
1async waitForPortReady(
2 port: number,
3 options?: WaitOptions & { intervalMs?: number; host?: string },
4): Promise<this>

Polls a TCP port from inside the sandbox (via bash's /dev/tcp shim) until something is listening. Resolves once the port accepts a connection; throws CreateosSandboxTimeoutError if the budget runs out. Requires bash and GNU timeout in the rootfs (both present in the default rootfs).

Parameters

NameTypeDescription
portnumberPort to probe (1-65535).
options.timeoutMs?numberWait budget in ms. Default 30000.
options.intervalMs?numberPoll interval in ms. Default 200.
options.host?stringHost to probe inside the sandbox. Default "127.0.0.1".
options.signal?AbortSignalCancels the wait.
options.request?RequestOptionsPer-poll request options.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.runCommand("sh", ["-c", "python3 -m http.server 8080 &"]);
2await sandbox.waitForPortReady(8080, { timeoutMs: 10_000 });
3console.log("server is up");

previewUrl

TypeScript
1previewUrl(port: number, options?: { scheme?: "http" | "https" }): string

Builds the public ingress URL for a port. Only available when the sandbox was created with ingress_enabled: true (or enabled later via setIngress(true)). Synchronous, no network call.

Parameters

NameTypeDescription
portnumberIn-guest port to route to (1-65535).
options.scheme?"http" | "https"URL scheme. Default "https". Pass "http" when the TLS certificate is not yet provisioned.

Returns string: fully-qualified public URL.

Throws CreateosSandboxError: port invalid or ingress not enabled.

Example

TypeScript
1await sandbox.setIngress(true);
2const url = sandbox.previewUrl(3000);
3// TLS cert may lag on fresh hostname — force http:
4const plain = sandbox.previewUrl(3000, { scheme: "http" });

Egress & bandwidth

getEgress

TypeScript
1getEgress(options?: RequestOptions): Promise<EgressView>

Returns the current egress allowlist and counters. EgressView.egress is [] when all egress is allowed.

Parameters: options?: RequestOptions.

Returns Promise<EgressView>: { id: string; egress: string[] }.

Throws

Example

TypeScript
1const { egress } = await sandbox.getEgress();
2console.log(egress); // ["api.openai.com:443"]

setEgress

TypeScript
1setEgress(rules: string[] | null, options?: RequestOptions): Promise<EgressView>

Replaces the egress allowlist. null or [] means allow all egress.

Parameters

NameTypeDescription
rulesstring[] | nullhost:port allow rules, or null/[] to allow all.
options?RequestOptionsPer-request options.

Returns Promise<EgressView>

Throws

Example

TypeScript
1await sandbox.setEgress(["api.openai.com:443", "registry.npmjs.org:443"]);
2await sandbox.setEgress(null); // allow all

getBandwidth

TypeScript
1getBandwidth(options?: RequestOptions): Promise<BandwidthView>

Returns the current bandwidth quota and usage.

Parameters: options?: RequestOptions.

Returns Promise<BandwidthView>:

FieldTypeDescription
idstringSandbox id.
quota_bytesnumberTotal transferable quota. -1 = unmetered.
used_bytesnumberEgress bytes billed against the quota.
ingress_bytesnumberInbound bytes (observed, not enforced).
remaining_bytesnumberBytes left before capping.
cappedbooleantrue once quota is exhausted and egress is blocked.

Throws

Example

TypeScript
1const bw = await sandbox.getBandwidth();
2console.log(bw.used_bytes, "/", bw.quota_bytes);

rechargeBandwidth

TypeScript
1rechargeBandwidth(addBytes: number, options?: RequestOptions): Promise<BandwidthView>

Tops up the bandwidth quota by addBytes. Use this when BandwidthView.capped is true or you want to pre-purchase headroom. Note: bandwidth_quota_bytes is not settable at create time (the server rejects non-zero values); grow it post-create with this method.

Parameters

NameTypeDescription
addBytesnumberBytes to add to the quota.
options?RequestOptionsPer-request options.

Returns Promise<BandwidthView>: updated quota state.

Throws

Example

TypeScript
1await sandbox.rechargeBandwidth(10 * 1024 * 1024 * 1024); // +10 GiB

Networks

attachNetwork

TypeScript
1attachNetwork(networkId: string, options?: RequestOptions): Promise<OKResponse>

Attaches the sandbox to an overlay network.

Parameters

NameTypeDescription
networkIdstringNetwork id (e.g. "net_01h…").
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>: { ok: boolean }.

Throws

Example

TypeScript
1await sandbox.attachNetwork("net_01h…");

detachNetwork

TypeScript
1detachNetwork(networkId: string, options?: RequestOptions): Promise<OKResponse>

Detaches the sandbox from an overlay network.

Parameters

NameTypeDescription
networkIdstringNetwork id to detach from.
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>

Throws

Example

TypeScript
1await sandbox.detachNetwork("net_01h…");

Disks

listDisks

TypeScript
1listDisks(options?: RequestOptions): Promise<SandboxDiskView[]>

Lists all disks attached to the sandbox with per-attachment mount status. Fetches all pages before returning.

Parameters: options?: RequestOptions.

Returns Promise<SandboxDiskView[]> where each entry has:

FieldTypeDescription
disk_idstringdisk_<ulid> id.
namestringDisk name.
kindDiskKindDisk kind.
configDiskConfigDisk config.
mount_pathstringAbsolute guest path.
sub_path?stringBucket sub-folder exposed at mount_path.
mount_statusDiskMountStatusCurrent mount state.
mount_error?stringFailure detail when mount_status is "error".

Throws

Example

TypeScript
1const disks = await sandbox.listDisks();
2for (const d of disks) {
3 console.log(d.disk_id, d.mount_path, d.mount_status);
4}

iterateDisks

TypeScript
1iterateDisks(options?: RequestOptions): AsyncGenerator<SandboxDiskView>

Streams disks one page at a time. Prefer over listDisks() when the attached disk count may be large.

Parameters: options?: RequestOptions.

Returns AsyncGenerator<SandboxDiskView>

Example

TypeScript
1for await (const d of sandbox.iterateDisks()) console.log(d.disk_id, d.mount_path);

attachDisk

TypeScript
1attachDisk(opts: AttachDiskOptions, options?: RequestOptions): Promise<OKResponse>

Live-attaches a registered disk into the running sandbox. The server rejects with 409 if the sandbox is not running: paused sandboxes pick up new mounts on resume via CreateSandboxRequest.disks at create or fork time.

Parameters

NameTypeDescription
opts.diskIdstringA disk_<ulid> id or the user-scoped disk name.
opts.mountPathstringAbsolute path inside the guest, e.g. /mnt/data.
opts.subPath?stringBucket sub-folder to expose at mountPath.
options?RequestOptionsPer-request options.

Returns Promise<OKResponse>

Throws

Example

TypeScript
1await sandbox.attachDisk({ diskId: "shared-data", mountPath: "/mnt/data" });

detachDisk

TypeScript
1detachDisk(opts: DetachDiskOptions, options?: RequestOptions): Promise<DiskDetachedResponse>

Detaches a disk from this sandbox. mountPath is required because the same disk may be mounted at multiple paths (the composite key is (sandbox, disk, mountPath)). Bucket contents are untouched.

Parameters

NameTypeDescription
opts.diskIdstringA disk_<ulid> id or the user-scoped disk name.
opts.mountPathstringAbsolute path where the disk is currently mounted.
options?RequestOptionsPer-request options.

Returns Promise<DiskDetachedResponse>: { detached: boolean }.

Throws

Example

TypeScript
1await sandbox.detachDisk({ diskId: "shared-data", mountPath: "/mnt/data" });

SSH

addSSHPubkeys

TypeScript
1addSSHPubkeys(keys: string[], options?: RequestOptions): Promise<AddSSHPubkeysResponse>

Adds OpenSSH public keys to this sandbox's authorized set. Keys already present are de-duplicated server-side. Works on a live (running) sandbox, unlike CreateSandboxRequest.ssh_pubkeys which is set only at create time.

Parameters

NameTypeDescription
keysstring[]OpenSSH public key strings (e.g. "ssh-ed25519 AAAA…").
options?RequestOptionsPer-request options.

Returns Promise<AddSSHPubkeysResponse>: { count: number }, the total authorized keys after the add.

Throws

Example

TypeScript
1const pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA…";
2const { count } = await sandbox.addSSHPubkeys([pubkey]);
3console.log(`${count} key(s) authorized`);

Introspection

refresh

TypeScript
1async refresh(options?: RequestOptions): Promise<this>

Re-fetches the sandbox projection and updates this handle in place. Use after an out-of-band mutation or to verify state before acting.

Parameters: options?: RequestOptions.

Returns Promise<this>

Throws

Example

TypeScript
1await sandbox.refresh();
2console.log(sandbox.status);

toJSON

TypeScript
1toJSON(): SandboxView

Returns the last-known sandbox projection. Called automatically by JSON.stringify. No network call.

Returns SandboxView

Example

TypeScript
1console.log(JSON.stringify(sandbox, null, 2));

For file transfer operations on the sandbox filesystem, see Sandbox Files.

See also

  • Client: createSandbox, getSandbox, listSandboxes, and the sub-API namespaces.
  • Errors: full error class hierarchy.
  • Types: all wire types and option interfaces.
  • Sub-APIs: TemplatesApi, NetworksApi, DisksApi.

100,000+ Builders. One Platform.

Get product updates, builder stories, and early access to features that help you ship faster.

NodeOps is the agentic operating system for production AI. CreateOS is its flagship product.