Quickstart
Install the CLI, get an API key, and run your first sandbox in about a minute.
This walks through everything in the 60-second version on the intro page, plus the parts that get skipped there: where the API key actually comes from, and what fork/pause are for.
1. Install the CLI#
$ npx sandal initsandal init scaffolds a minimal project, asks which SDK you want (TypeScript, Python, or Go), and writes a starter file with a working sandboxes.create call already in it. No global install required, npx pulls it on demand.
If you'd rather install the CLI standalone:
$ npm install -g sandal
$ sandal --version2. Get an API key#
$ sandal loginThis opens your browser to sandal.dev, and drops a scoped API key into ~/.sandal/credentials (and prints it once, so you can put it in CI secrets). You can also generate keys from the dashboard under Settings → API Keys.
Export it for local use:
export SANDAL_API_KEY="sk_live_..."In CI, set it as a repository secret and reference it as an env var, never commit it.
3. Create a sandbox#
npm install @sandal/sdkimport { Sandal } from "@sandal/sdk";
const sandal = new Sandal({ apiKey: process.env.SANDAL_API_KEY });
const sb = await sandal.sandboxes.create({ template: "node-24" });
console.log(sb.id);Cold create targets under 1 second, the microVM boots with its own kernel, not a shared container runtime. If you're claiming from a warm pool instead of creating cold, that drops to under 200ms.
4. Run commands and touch the filesystem#
const result = await sb.exec("pnpm install && pnpm test");
console.log(result.stdout, result.exitCode);
await sb.fs.write("/app/config.json", JSON.stringify({ debug: true }));
const contents = await sb.fs.read("/app/config.json");exec runs synchronously inside the sandbox and returns stdout, stderr, and exit code. fs gives you direct read/write against the sandbox's filesystem without shelling out.
5. Expose a port#
If your sandbox is running a dev server, expose it as a public HTTPS URL:
const url = await sb.expose(3000);
console.log(url); // https://3000-sb_xxxx.sandal.dev6. Pause and fork#
Sandboxes bill per second while they are running. When you're done for now but want to come back to the exact same state:
await sb.pause(); // billing drops to $0
// ...later...
await sb.resume(); // restores from the last incremental snapshotNeed a second, independent copy of the same state, for parallel test runs, or to let two agents branch off the same checkpoint?
const child = await sb.fork();Snapshots are incremental and taken per minute, so resume/fork restore lazily with prefetch rather than replaying the whole disk. See Snapshots and forks for how that works.
Next steps#
- Sandboxes, the full API surface: templates, networking, limits
- Runners, point
runs-on:at Sandal instead of GitHub-hosted runners - Simulators, same SDK, iOS/Android devices instead of Linux VMs
- SDK reference: TypeScript / Python
- CLI reference, every
sandalsubcommand - Pricing, per-second, active-CPU + provisioned-RAM metering, no plan minimums