|
| 1 | +--- |
| 2 | +title: "Sandbox Lifetimes" |
| 3 | +description: "Understand how long sandboxes stay alive, how to extend or reconnect to them, and when to promote work to a Deploy app." |
| 4 | +--- |
| 5 | + |
| 6 | +Sandboxes are intentionally ephemeral. They boot in milliseconds, serve their |
| 7 | +purpose, and disappear—reducing the blast radius of untrusted code and removing |
| 8 | +infrastructure chores. Still, you can control exactly how long a sandbox stays |
| 9 | +alive and even reconnect later when debugging is required. |
| 10 | + |
| 11 | +## Default lifetime: `"session"` |
| 12 | + |
| 13 | +```tsx |
| 14 | +await using sandbox = await Sandbox.create(); |
| 15 | +``` |
| 16 | + |
| 17 | +With no options set, the sandbox lives for the duration of your script. Once the |
| 18 | +`Sandbox` instance is closed, the microVM shuts down and frees all resources. |
| 19 | +This keeps costs predictable and prevents orphaned infrastructure. |
| 20 | + |
| 21 | +## Duration-based lifetimes |
| 22 | + |
| 23 | +Provide a duration string to keep a sandbox alive after the client disconnects: |
| 24 | + |
| 25 | +```tsx |
| 26 | +const sandbox = await Sandbox.create({ lifetime: "5m" }); |
| 27 | +const id = sandbox.id; |
| 28 | +await sandbox.close(); // process can exit now |
| 29 | + |
| 30 | +// later |
| 31 | +const reconnected = await Sandbox.connect({ id }); |
| 32 | +``` |
| 33 | + |
| 34 | +Supported suffixes: `s` (seconds) and `m` (minutes). Examples: `"30s"`, `"5m"`, |
| 35 | +`"90s"`. Use this mode for manual inspection, SSH debugging, or when a bot needs |
| 36 | +to resume work mid-way. |
| 37 | + |
| 38 | +## Forcefully ending a sandbox |
| 39 | + |
| 40 | +- `await sandbox.kill()` immediately stops the VM and releases the lifetime. |
| 41 | +- Killing a sandbox invalidates exposed HTTP URLs, SSH sessions, and any |
| 42 | + attached volumes. |
| 43 | + |
| 44 | +## Ephemeral compute vs Deploy apps |
| 45 | + |
| 46 | +| Aspect | Sandboxes | Deploy Apps | |
| 47 | +| ------------- | ---------------------------------------- | -------------------------------------- | |
| 48 | +| Lifetime | Seconds to minutes | Always-on, managed rollouts | |
| 49 | +| Control plane | Programmatic via SDK | Dashboard + CI/CD | |
| 50 | +| Use cases | Agents, previews, untrusted code | Production APIs, long-lived services | |
| 51 | +| State | Ephemeral (use volumes when needed) | Durable deployments with KV, databases | |
| 52 | +| Exposure | `exposeHttp()`/`exposeSsh()` per sandbox | Custom domains, TLS, routing built-in | |
| 53 | + |
| 54 | +Start in a sandbox to iterate quickly. Once the codebase stabilizes and needs |
| 55 | +24/7 availability, promote it to a Deploy app where builds, rollouts, and |
| 56 | +observability are managed for you. |
| 57 | + |
| 58 | +## Promote with `sandbox.deploy()` |
| 59 | + |
| 60 | +When a sandbox proves the concept, you can turn it into an always-on Deploy app |
| 61 | +without rebuilding elsewhere. `sandbox.deploy()` snapshots the current file |
| 62 | +system, carries over `allowNet`, and provisions an app with a durable URL, |
| 63 | +observability, and team access. |
| 64 | + |
| 65 | +```tsx |
| 66 | +await using sandbox = await Sandbox.create({ lifetime: "10m" }); |
| 67 | +// ...build or scaffold your service... |
| 68 | + |
| 69 | +const app = await sandbox.deploy({ |
| 70 | + name: "ai-preview", |
| 71 | + entrypoint: "server.ts", |
| 72 | +}); |
| 73 | +console.log(`Promoted to Deploy app ${app.slug}`); |
| 74 | +``` |
| 75 | + |
| 76 | +Reasons to promote: |
| 77 | + |
| 78 | +- Keep a sandbox experiment running for customer traffic with production SLAs. |
| 79 | +- Get TLS, custom domains, rollbacks, and traffic splitting handled for you. |
| 80 | +- Share observability (logs/traces/metrics) across the team via the Deploy UI. |
| 81 | +- Replace brittle hand-offs; the exact sandbox state becomes the deployed |
| 82 | + revision. |
| 83 | + |
| 84 | +Use sandboxes for rapid, ephemeral work, then call `sandbox.deploy()` when the |
| 85 | +code should live as a managed service. |
| 86 | + |
| 87 | +## Lifetime best practices |
| 88 | + |
| 89 | +- Keep lifetimes short for untrusted or user-supplied code. Smaller windows |
| 90 | + reduce attack surface. |
| 91 | +- Use metadata (e.g., `metadata: { owner: "agent-42" }`) to track who owns a |
| 92 | + sandbox that outlives its creator. |
| 93 | +- Pair longer lifetimes with explicit `allowNet` rules and rate limits if |
| 94 | + running internet-facing workloads. |
| 95 | +- Clean up proactively: scripts should call `kill()` once the workload ends, |
| 96 | + rather than waiting for the duration to expire. |
| 97 | + |
| 98 | +## Related APIs |
| 99 | + |
| 100 | +- [`Sandbox.create()`](./create.md) – pass the `lifetime` option when |
| 101 | + provisioning. |
| 102 | +- `Sandbox.connect({ id })` – resume control of a duration-based sandbox. |
| 103 | +- `Sandbox.kill()` – terminate early. |
| 104 | +- [`Expose HTTP`](./expose_http.md) and [`Expose SSH`](./expose_ssh.md) – note |
| 105 | + that their URLs/credentials die with the sandbox lifetime. |
0 commit comments