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 init

sandal 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 --version

2. Get an API key#

$ sandal login

This 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/sdk
import { 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.dev

6. 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 snapshot

Need 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#