Sandboxes quickstart
Use Lizard SDK to create a sandbox, run Python, write a file and open a port, then stop the sandbox. Each step has TypeScript and Python code. You need a Lizard account on Pro or the trial, an API key and a project. To learn what Sandboxes are first, read the overview.
Install and authenticate
Install the Lizard SDK and create an API key in Settings → API keys, or with lizard keys create <name>. Store it in LIZARD_API_KEY. Every sandbox belongs to a project; the examples pass its ID as projectId (Python: project_id), and project also accepts a slug or name.
npm install @lizard-build/sdk
pip install lizard-sdk
export LIZARD_API_KEY="<your-api-key>"Run a command
Sandbox.create boots a sandbox from a template, here interpreter, which has Python and common data libraries. timeoutMs sets its lifetime; the SDK default is five minutes.
import { Sandbox } from '@lizard-build/sdk';
const sandbox = await Sandbox.create('interpreter', {
projectId: 'proj_123', timeoutMs: 300_000,
});
try {
const result = await sandbox.process.exec("python -c 'print(2 ** 10)'");
console.log(result.stdout, result.stderr, result.exitCode);
} finally {
await sandbox.kill();
}from lizard import Sandbox
sandbox = Sandbox.create("interpreter", project_id="proj_123", timeout_ms=300_000)
try:
result = sandbox.process.exec_("python -c 'print(2 ** 10)'")
print(result.stdout, result.stderr, result.exit_code)
finally:
sandbox.kill()A nonzero exit code is a result, not an error: check exitCode (Python: exit_code) yourself.
Files
Write text or bytes with fs.write, read text with fs.read, and read bytes with fs.readBytes (Python: read_bytes). Files live only as long as the sandbox, unless you write them to a Persistent Volume at /workspace.
await sandbox.fs.write("/tmp/task.py", "print(42)\n");
const result = await sandbox.process.exec("python /tmp/task.py");
console.log(result.stdout);sandbox.fs.write("/tmp/task.py", "print(42)\n")
result = sandbox.process.exec_("python /tmp/task.py")
print(result.stdout)Public ports
Start a server that listens on 0.0.0.0, then call exposePort(port) (Python: expose_port). It returns url, hostname, and accessToken. The port is private: open url in a browser (it carries ?lizard_token=), or send the token in the X-Lizard-Access-Token header. Requests without the token get 401. A stopped sandbox no longer serves the port. See preview URLs for a dev server an agent built.
await sandbox.process.exec(
"nohup python -m http.server 3000 --bind 0.0.0.0 --directory /tmp >/tmp/http.log 2>&1 </dev/null &",
);
const { url, hostname, accessToken } = await sandbox.exposePort(3000);
console.log(url); // open in a browser
const res = await fetch(`https://${hostname}/`, {
headers: { 'X-Lizard-Access-Token': accessToken },
});sandbox.process.exec_(
"nohup python -m http.server 3000 --bind 0.0.0.0 --directory /tmp >/tmp/http.log 2>&1 </dev/null &"
)
exposed = sandbox.expose_port(3000)
print(exposed.url) # open in a browserReconnect to a running sandbox
Keep the sandbox ID (sandbox.sandboxId, Python: sandbox.sandbox_id) and call Sandbox.connect(id) from another process or a later request to get a handle to the same sandbox. connect only checks that the sandbox exists: it does not resume a paused sandbox, and it throws NotFoundError once the sandbox has been killed or has expired.
const connected = await Sandbox.connect(sandbox.sandboxId);
console.log(await connected.getInfo());connected = Sandbox.connect(sandbox.sandbox_id)
print(connected.get_info())Pause, resume, and snapshots
pause() saves the sandbox’s memory and running processes and keeps /workspace on its node. A successful pause stops compute charges; Persistent Volumes storage continues to be billed. resume() restores the sandbox with the same ID and restarts compute billing. Both calls queue the work and return at once; wait for paused or running to confirm success.
await sandbox.pause();
await sandbox.waitForStatus('paused');
await sandbox.resume();
await sandbox.waitForStatus('running');- Pausing closes open network connections. Programs in the sandbox must reconnect after a resume.
- If the processes cannot be saved, the sandbox keeps running and
waitForStatusthrows with the reason. If a resume fails, the sandbox stays paused with its checkpoint; callresume()again. - The lifetime deadline stops while the sandbox is paused and continues after the resume. A paused sandbox does not count toward the running limit.
- A paused sandbox resumes on the same node. If that node fails, the paused state is lost; export files you need.
A snapshot saves a running sandbox’s memory and /workspace files as a private template in its project. Each restore starts a new sandbox in the snapshot’s region. Close clients and terminals and stop writes to /workspace before you capture. Attached Persistent Volumes are not captured.
const saved = await sandbox.snapshot('my-app', { poolSize: 5 });
await Sandbox.waitForSnapshot(saved.id);
const copy = await Sandbox.restore(saved.id);A snapshot of a Firecracker sandbox is ready when the call returns and restores from disk, so poolSize does not apply. Each restore runs at the source’s size and bills at that size’s hourly price. A snapshot of a pod sandbox keeps warm copies, five by default (one to ten); when none is ready, restore can return HTTP 503 until the pool refills, and the restored sandbox is billed by measured usage. In both cases size does not apply to a restore. In the CLI, use lizard sandbox pause <id>, lizard sandbox resume <id>, lizard sandbox snapshot <id> --name my-app, and lizard sandbox restore <snapshot-id>.
Clean up and next steps
Call kill() when the task ends, as the examples do in finally. In Python, with Sandbox.create(...) as sandbox: kills the sandbox when the block exits. A sandbox you forget stops at its deadline, five minutes after creation unless you set another lifetime; see resources and timeouts.
- Every call, option and error: Sandbox API and SDK reference.
- Code from an LLM with state between calls: code interpreter.
- Files that outlive a sandbox: Persistent Volumes.
- A coding agent in a sandbox: Claude Code or OpenCode.
- The same steps from a terminal:
lizard sandbox. In the browser: the Sandboxes dashboard. - Sizes, prices and how many sandboxes can run at once: limits. Product overview and comparison: Sandboxes.
Updated