DocsSandbox lifecycle

Sandbox lifecycle

Create a sandbox, reconnect to it from somewhere else, find it again in a list, and kill it when you are done.

Create a sandbox

Sandbox.create() starts a new sandbox from a template and resolves once the sandbox has been created. The default template is base. Both SDKs read your key from IMPELLO_API_KEY.

import { Sandbox } from '@impello/sdk'

const sandbox = await Sandbox.create('base', {
  timeoutMs: 600_000,
  metadata: { run: 'nightly-42' },
  envs: { NODE_ENV: 'production' },
})

console.log(sandbox.sandboxId)

The timeout is in milliseconds in TypeScript and in seconds in Python. A sandbox that reaches its timeout is killed unless you set lifecycle. See Timeouts.

Every running sandbox counts against your plan's concurrency limit: 3 at once on Micro, 10 on Base, 100 on Scale. Paused sandboxes do not count, and there is no limit on how many you keep paused. See Limits and pricing.

Options

TypeScriptPythonDefaultWhat it does
templatetemplate'base'Template name or ID. See Templates.
timeoutMstimeout300_000 / 300How long the sandbox lives. The maximum depends on your plan; see Limits and pricing.
metadatametadata{}String key-value pairs stored with the sandbox. Filterable in list.
envsenvs{}Environment variables set for every command run in the sandbox.
securesecuretrueRequire a per-sandbox access token on every command, file and terminal call (the sandbox's control channel). See Secured sandboxes.
allowInternetAccessallow_internet_accesstrueOutbound internet. false is the same as denying all egress in network.
networknetworkEgress rules and public traffic. See Network and public URLs.
lifecyclelifecycleonTimeout: 'kill'Pause instead of kill on timeout. See Timeouts.

Metadata and environment variables

Metadata is for you: tag a sandbox with the user, job or run it belongs to, then find it again with list. Keys and values are strings. Anyone with one of your team's API keys can read them through getInfo and list.

Environment variables are for the sandbox: every command you run through the SDK sees them. They are ordinary process environment, not a secret store. A command can override them with its own envs.

import { Sandbox } from '@impello/sdk'

const sandbox = await Sandbox.create({
  metadata: { userId: 'u_123', job: 'index' },
  envs: { LOG_LEVEL: 'info' },
})

const a = await sandbox.commands.run('echo $LOG_LEVEL')
console.log(a.stdout) // info

const b = await sandbox.commands.run('echo $LOG_LEVEL', {
  envs: { LOG_LEVEL: 'debug' },
})
console.log(b.stdout) // debug

Secured sandboxes

A sandbox is created with secure: true unless you say otherwise. The SDK receives a token scoped to that one sandbox when it creates or connects to it, and sends the token with every command, file and terminal request. Upload and download URLs from uploadUrl() and downloadUrl() (upload_url() and download_url() in Python) are signed with the same token, and only a secured sandbox accepts a signature expiry. secure covers the control channel only — a server you start on a port is still reachable by anyone who knows the sandbox ID unless you also set network.allowPublicTraffic: false. See Network and public URLs.

Set secure: false only when something other than the SDK has to call the sandbox directly and cannot carry the token. Such a sandbox has no access token, and its file URLs are unsigned.

Connect to a running sandbox

Sandbox.connect(sandboxId) returns a client for a sandbox that already exists. Use it to reach the same sandbox from another process, a queue worker or a serverless function. If the sandbox is paused, connect resumes it. In the snippets from here on, sandboxId (sandbox_id in Python) is the ID of a sandbox you already have, and sandbox is the client the previous snippet created.

import { Sandbox } from '@impello/sdk'

const sandbox = await Sandbox.connect(sandboxId, { timeoutMs: 600_000 })
const result = await sandbox.commands.run('uptime')
console.log(result.stdout)

The sandbox must be running or paused. Otherwise connect throws SandboxNotFoundError (SandboxNotFoundException in Python). See Errors.

An instance you already hold has the same method: await sandbox.connect() in TypeScript and sandbox.connect() in Python. It is the shortest way to resume a sandbox you paused a moment ago. See Pause, resume and snapshots.

Get sandbox information

getInfo() (get_info() in Python) fetches the current record for a sandbox: its state, template, metadata and when it will time out.

import { Sandbox } from '@impello/sdk'

const info = await sandbox.getInfo()
console.log(info.state, info.endAt, info.metadata)

// Or by ID, without a client
const same = await Sandbox.getInfo(sandboxId)

Common fields

TypeScriptPythonMeaning
sandboxIdsandbox_idThe sandbox ID.
templateIdtemplate_idID of the template it was created from.
namenameTemplate name, when the template has one.
metadatametadataThe metadata you set at create.
startedAtstarted_atWhen the sandbox started.
endAtend_atWhen the current timeout expires.
statestaterunning or paused.
cpuCountcpu_countvCPUs.
memoryMBmemory_mbMemory in MiB.
allowInternetAccessallow_internet_accessWhether outbound internet was allowed at create.
networknetworkThe egress and public traffic settings.
lifecyclelifecycleWhat happens on timeout, and whether it auto-resumes.
sandboxDomainsandbox_domainHost the sandbox is served from.

isRunning() (is_running() in Python) asks the sandbox itself rather than the control API. It returns false when the sandbox is no longer answering and raises on any other transport or auth failure.

List sandboxes

Sandbox.list() returns a paginator over your team's sandboxes. With no filter it includes both running and paused sandboxes, 100 per page; 100 is also the largest page the API will return. Pages come back from nextItems() (next_items() in Python) while hasNext (has_next) is true.

import { Sandbox } from '@impello/sdk'

const paginator = Sandbox.list({
  query: {
    metadata: { userId: 'u_123', job: 'index' },
    state: ['running'],
  },
  limit: 50,
})

while (paginator.hasNext) {
  const page = await paginator.nextItems()
  for (const s of page) {
    console.log(s.sandboxId, s.state, s.endAt)
  }
}

Metadata filters are combined with AND: a sandbox must match every pair. state takes any of running and paused. Listed entries carry the same fields as getInfo minus network, lifecycle, allowInternetAccess and sandboxDomain; call getInfo on one entry when you need those.

The dashboard shows the same list at dashboard.impello.ai/sandboxes.

Kill a sandbox

kill() stops the sandbox and frees it. It returns true when the sandbox was killed and false when no such sandbox exists, so killing twice is safe.

import { Sandbox } from '@impello/sdk'

await sandbox.kill()

// Or by ID, without a client
await Sandbox.kill(sandboxId)

In Python, Sandbox is a context manager that kills the sandbox on exit:

from impello import Sandbox

with Sandbox.create() as sandbox:
    print(sandbox.commands.run("echo hello").stdout)
# killed here

Async Python

Every call on this page has an AsyncSandbox form with the same name, awaited: await AsyncSandbox.create(), await AsyncSandbox.connect(sandbox_id), await sandbox.get_info(), await sandbox.kill(). AsyncSandbox.list() returns an AsyncSandboxPaginator whose next_items() is awaited, and the context manager is async with await AsyncSandbox.create() as sandbox:.

Next: Run commands.