Skip to content

Pause & Resume

Pause and resume is one of Runra Sandbox’s most powerful features. It lets you preserve the full state of a sandbox — filesystem, running processes, environment variables, and port mappings — without keeping the sandbox actively running (and billing).

When you pause a sandbox:

  1. All processes inside are checkpointed
  2. The full filesystem is snapshotted
  3. Environment variables and port mappings are saved as metadata
  4. The underlying VM resources are released
  5. You stop incurring active runtime costs

When you resume:

  1. A new VM is provisioned from the snapshot
  2. The filesystem is restored exactly as it was
  3. Processes that were checkpointed are restored
  4. Port mappings are re-established
  5. The sandbox returns to running state
create → [running] → pause → [paused] → resume → [running]
↑ ↓
└────────── terminate ──────────────┘
const sandbox = await runra.sandboxes.create({
image: "node:22",
resources: { cpu: 2, memoryMb: 4096 },
});
await sandbox.exec("npm install && npm run build");
// Pause preserves the installed dependencies and build artifacts
await sandbox.pause();
console.log(sandbox.state); // "paused"
const resumed = await runra.sandboxes.resume(sandbox.id);
console.log(resumed.state); // "running"
// All files from the previous session are still there
const result = await resumed.exec("ls node_modules");
console.log(result.stdout); // node_modules directory listing
const sandbox = await runra.sandboxes.get(sandbox.id);
console.log(sandbox.state); // "running" | "paused" | "terminated"
const pausedSandboxes = await runra.sandboxes.list({
state: "paused",
limit: 50,
});
for (const sb of pausedSandboxes) {
console.log(`Sandbox ${sb.id}: paused at ${sb.pausedAt}`);
}

Agents working on complex refactors across multiple sessions can pause between sessions:

// Monday session
const sandbox = await runra.sandboxes.create({ image: "node:22" });
await sandbox.exec("git clone https://github.com/acme/monolith.git");
await sandbox.exec("cd monolith && npm install");
// Agent works for a few hours...
await sandbox.pause();
// Tuesday session — picks up exactly where it left off
const resumed = await runra.sandboxes.resume(sandbox.id);
await resumed.exec("cd monolith && git status");
// Working tree clean, all work from Monday preserved

Give each user a persistent sandbox that remembers their state:

async function getUserSandbox(userId: string) {
// Check if user already has a paused sandbox
const existing = await runra.sandboxes.list({
metadata: { userId },
state: "paused",
limit: 1,
});
if (existing.length > 0) {
return runra.sandboxes.resume(existing[0].id);
}
return runra.sandboxes.create({
image: "python:3.12",
metadata: { userId },
resources: { cpu: 2, memoryMb: 4096 },
});
}

Data scientists can run multi-stage experiments with state preserved between stages:

const sandbox = await runra.sandboxes.create({ image: "python:3.12" });
// Stage 1: Data loading and cleaning
await sandbox.exec("python load_data.py");
await sandbox.exec("python clean_data.py");
await sandbox.pause();
// Stage 2: Model training (resumed, data already cleaned)
const stage2 = await runra.sandboxes.resume(sandbox.id);
await stage2.exec("python train_model.py --epochs 50");
await stage2.pause();
// Stage 3: Evaluation
const stage3 = await runra.sandboxes.resume(sandbox.id);
const result = await stage3.exec("python evaluate.py");

Scheduled jobs that need to maintain state across runs:

// Cron job runs every hour
async function hourlyCrawl() {
const sandbox = await getOrResumeSandbox("crawler-sandbox");
await sandbox.exec("python crawl.py --resume");
await sandbox.pause(); // Ready for next hour
}

Agents that modify files and need those modifications to persist across tool calls:

const sandbox = await runra.sandboxes.create({ image: "node:22" });
async function agentToolLoop(instruction: string) {
let sandbox = await runra.sandboxes.resume(sessionStore.get("sandboxId"));
const tools = {
writeFile: async (path, content) => sandbox.files.write(path, content),
runCommand: async (cmd) => sandbox.exec(cmd),
readFile: async (path) => sandbox.files.read(path),
};
// Agent uses tools, all changes persist in sandbox
await runAgentLoop(instruction, tools);
await sandbox.pause(); // State preserved for next invocation
}

Keep development environments ready without paying for idle time:

// Create once, use when needed
async function getDevSandbox(projectId: string) {
const sandbox = await runra.sandboxes.resume(`dev-${projectId}`);
// Auto-pause after 30 minutes of inactivity
sandbox.on("idle", { thresholdMs: 1_800_000 }, async () => {
await sandbox.pause();
console.log(`Sandbox ${sandbox.id} auto-paused to save costs`);
});
return sandbox;
}
StateBilled?Rate
runningYesPer-second active runtime
pausedYesReduced storage-only rate
terminatedNoN/A

Paused sandboxes incur a minimal storage fee. The active runtime rate is significantly higher than the storage rate, so pausing idle sandboxes can yield substantial cost savings.

Track pause and resume via observability:

sandbox.on("paused", (event) => {
console.log(`Sandbox paused. Runtime: ${event.runtimeMs}ms`);
});
sandbox.on("resumed", (event) => {
console.log(`Sandbox resumed. Paused duration: ${event.pausedDurationMs}ms`);
});