---
title: "Sandbox SDK lifecycle"
canonical: https://trickest.com/docs/developer-tools/sandbox-sdk/lifecycle
description: "Create persistent sandboxes, stop and resume them, and delete environments when work ends."
---

# Sandbox SDK lifecycle

`Sandbox.create()` defaults `persistent` to `true`. Set it explicitly when your application needs to resume work later.

## Choose the end of the lifecycle

| Operation                                       | Result                                                                                           |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `Sandbox.create({ token, persistent: true })`   | Request an environment that can retain its working directory through stop/resume |
| `sandbox.stop()`                                | Stop compute; a persistent environment can resume, while a non-persistent environment terminates |
| `Sandbox.get({ token, id })`                    | Retrieve the environment, automatically resuming a stopped persistent sandbox                    |
| `Sandbox.get({ token, id, autoResume: false })` | Inspect recorded state without requesting auto-resume                                            |
| `sandbox.delete()`                              | Retire the sandbox permanently; it cannot resume                                                 |

Keep the returned `sandboxId` to retrieve the environment later. You can also
look it up by name. A handle's `status` is cached, not a live feed. `stop()`
refreshes that handle after its request; use `Sandbox.get()` for a fresh read.

## Stop and resume the same environment

This example writes a marker, stops the environment, resumes it by ID, and checks the retained file. It attempts to delete the sandbox when the check finishes.

```typescript
import { Sandbox } from "@trickest/sandbox";

export async function checkRetainedWork(token: string): Promise<void> {
  const sandbox = await Sandbox.create({
    token,
    runtime: "node24",
    persistent: true,
    timeout: 5 * 60_000,
  });
  console.log("Sandbox ID:", sandbox.sandboxId);
  try {
    await sandbox.writeFile("progress.txt", "step one complete");
    await sandbox.stop();

    const paused = await Sandbox.get({
      token,
      id: sandbox.sandboxId,
      autoResume: false,
    });
    console.log("Recorded state:", paused.status);

    const resumed = await Sandbox.get({ token, id: sandbox.sandboxId });
    const progress = await resumed.readFileToBuffer({ path: "progress.txt" });
    if (progress === null) throw new Error("Retained progress is missing");
    console.log(new TextDecoder().decode(progress));
  } finally {
    await sandbox.delete();
  }
}
```

Retain the sandbox ID so you can retry deletion if cleanup fails. A deletion error in `finally` can mask the original failure; record both separately in production code.

Retention covers the working directory at `/trickest/sandbox`, not the entire
guest or container filesystem. Files under other paths and system packages
installed outside that directory can disappear when the container is recreated.
Retention also depends on the sandbox remaining available. Running processes do
not survive stopping the machine; restart them after resuming.

The creation option `timeout` requests a sandbox lease window in milliseconds.
Server policy controls enforcement and may shorten that window.
`extendTimeout(durationMs)` requests a renewal; it does not promise that a
long-running command will keep the sandbox alive. It differs from a command's
`timeoutMs`, which limits the client's wait. Always clean up explicitly and
download results before final deletion.

Control-plane requests have separate client deadlines: five minutes for creation and 25 seconds for get/list and stop/delete/extend. Override them through `TRICKEST_SANDBOX_CREATE_TIMEOUT_MS`, `TRICKEST_SANDBOX_GET_TIMEOUT_MS`, and `TRICKEST_SANDBOX_OP_TIMEOUT_MS`. A timed-out request does not prove that its server-side operation stopped. Choose a unique `name` when creating an environment. If creation times out, check `Sandbox.get({ token, name, autoResume: false })` or `Sandbox.list()` before retrying, because the first request may have completed.

## Find environments without resuming them

`Sandbox.list()` is cursor-paginated and does not auto-resume stopped environments. A list page contains handles and `nextCursor`; it is not an async iterable.

```typescript
import { Sandbox } from "@trickest/sandbox";

export async function listEnvironmentIds(token: string): Promise<string[]> {
  const ids: string[] = [];
  let cursor: string | undefined;
  do {
    const page = await Sandbox.list({ token, limit: 50, cursor });
    ids.push(...page.items.map((sandbox) => sandbox.sandboxId));
    cursor = page.nextCursor ?? undefined;
  } while (cursor);
  return ids;
}
```

## Snapshot limitations

Snapshots require a running environment and snapshot storage enabled for your vault. `snapshot()` captures a named restore point while the environment stays available; processes pause during capture. `listSnapshots()` returns named snapshots, newest first, and excludes the rolling snapshot.

| Method | Effect |
| --- | --- |
| `snapshot({ excludes })` | Capture a named snapshot, optionally excluding paths. |
| `updateRollingSnapshot()` | Replace the rolling snapshot. The default pauses processes during capture; `quiesce: "NONE"` captures without pausing. |
| `restoreSnapshot(snapshotId)` | Replace the current working state with a snapshot and start a fresh session. |
| `deleteSnapshot(snapshotId)` | Permanently delete a named snapshot; the rolling snapshot cannot be deleted this way. |
| `updateSnapshotPolicy({ snapshotExcludes, snapshotExpiration, keepLastSnapshots })` | Change automatic capture and retention settings. Supply only the fields to change. |

Restoring stops the current session **without capturing its latest state**. Save any work you need before restoring, and restart your application afterward. `Sandbox.create({ token, source: { type: "snapshot", snapshotId } })` can create another environment from a snapshot. `fork()` copies configuration and metadata, not files.

Use `isSnapshotUnavailable(error)` to detect disabled snapshots or unavailable vault storage. `isSandboxNotRunning(error)` means the environment needs a live session; `isCaptureInProgress(error)` means another capture is already underway. Back off before retrying a capture collision.

Rolling capture has a separate 90-second client deadline, configurable with `TRICKEST_SANDBOX_SNAPSHOT_TIMEOUT_MS`. Named capture uses the operation deadline; restore uses the creation deadline.

The [platform SDK's sessions](/docs/developer-tools/sdk/sandbox) manage the in-app agent's environment. Use those session methods when your task belongs to an agent conversation.

---
_Markdown source of https://trickest.com/docs/developer-tools/sandbox-sdk/lifecycle._
