Serverless Sandboxes
A serverless sandbox auto-stops when it goes idle and is transparently restarted on the next inbound HTTP, TCP, or TLS-SNI connection to one of its exposed ports. Long-lived sandboxes that only serve occasional traffic - preview deployments, per-user code environments, model endpoints - stop consuming CPU and memory between requests without losing their disk state or public URL.
Key Capabilities
Section titled “Key Capabilities”Because of scale-to-zero, serverless sandboxes enable you to build:
- Massive density hosting: Run thousands of isolated workspaces or container instances on a single physical node by reclaiming CPU and memory from idle environments.
- Vercel-style deployment platforms: Spin up instant-on web applications or frontend preview deployments that automatically sleep and wake up dynamically upon client requests.
- Neon-style serverless databases: Provision dedicated database instances (e.g. Postgres, Redis) per tenant that scale to zero when inactive and resume instantly when queries arrive.
- On-demand interactive environments: Deploy coding interview platforms, tutorials, web playgrounds, or secure burner browsers that only consume active resources.
Check the usecase sections to learn more.
What it does
Section titled “What it does”Set serverless: true on the sandbox's lifecycle alongside stopIfIdleFor. When the idle timer fires, the sandbox stops, but its exposed-port routes stay alive in a wake-aware shape and wake_armed is set in the store. The next inbound HTTP request or L4 connection through its public endpoint drives a cold start, then traffic is proxied to the started container.
| Aspect | Behavior |
|---|---|
| Idle trigger | stopIfIdleFor (required) - sandboxes stopped by lifecycle / age / involuntary exit re-arm for wake. |
| Manual stop | Calling stop explicitly clears wake_armed. The sandbox stays down until you start it again. |
| Cold-start latency | Hundreds of milliseconds to a few seconds, dominated by container start. |
| Cold-start timeout | 15s. After that, the ingress handler returns 503 Retry-After: 2. |
| Request body cap | 8 MiB. Larger requests during cold start are rejected with 413. |
| Protocols woken | HTTP, TCP, and TLS-SNI exposures. HTTP requests are buffered during cold start up to the body cap; TCP/TLS connections wait for wake and then stream bytes. |
The sandbox keeps its ID, public URL, environment, mounts, and disk across stop / wake cycles. Memory and in-process state do not survive - a serverless sandbox is more like a fast scale-to-zero container than a snapshot resume.
Enable per-sandbox
Section titled “Enable per-sandbox”stopIfIdleFor is required when serverless: true. The server rejects the request otherwise. Serverless wake rides the sandbox's public endpoints — a fully private sandbox has no routes to wake through. Calling exposePort (as below) opts the sandbox into public traffic automatically, so the usual create → expose flow needs no extra flag; only a serverless sandbox that never exposes a port would need allowPublicTraffic: true at create to be wakeable via its root URL. See Network Isolation.
const sandbox = await client.create({ image: 'ghcr.io/me/my-http-app:latest', lifecycle: { stopIfIdleFor: 5 * 60 * 1_000_000_000, // 5 minutes serverless: true, },})await sandbox.exposePort(8080)sandbox = client.create({ 'image': 'ghcr.io/me/my-http-app:latest', 'lifecycle': { 'stopIfIdleFor': 5 * 60 * 1_000_000_000, 'serverless': True, },})sandbox.expose_port(8080)sandbox, err := client.Create(ctx, sdktypes.CreateSandboxOptions{ Image: "ghcr.io/me/my-http-app:latest", Lifecycle: &sdktypes.Lifecycle{ StopIfIdleFor: 5 * time.Minute, Serverless: true, },})if err != nil { return err}_, err = sandbox.ExposePort(ctx, 8080)let sandbox = client.create(CreateOptions { image: "ghcr.io/me/my-http-app:latest".to_string(), lifecycle: Some(Lifecycle { stop_if_idle_for: 300_000_000_000, serverless: true, ..Default::default() }), ..Default::default()})?;sandbox.expose_port(8080)?;Sandbox sandbox = client.create( new CreateOptions() .setImage("ghcr.io/me/my-http-app:latest") .setLifecycle(new Lifecycle() .setStopIfIdleFor(300_000_000_000L) .setServerless(Boolean.TRUE)));sandbox.exposePort(8080);Update an existing sandbox
Section titled “Update an existing sandbox”The lifecycle update endpoint accepts the same field. Toggle serverless on or off on a running sandbox; the new policy takes effect at the next idle-window evaluation.
await sandbox.updateLifecycle({ stopIfIdleFor: 5 * 60 * 1_000_000_000, serverless: true,})sandbox.update_lifecycle({ 'stopIfIdleFor': 5 * 60 * 1_000_000_000, 'serverless': True,})err := sandbox.UpdateLifecycle(ctx, sdktypes.Lifecycle{ StopIfIdleFor: 5 * time.Minute, Serverless: true,})client.update_lifecycle(&sandbox.data.id, Lifecycle { stop_if_idle_for: 300_000_000_000, serverless: true, ..Default::default()})?;client.updateLifecycle(sandbox.id, new Lifecycle() .setStopIfIdleFor(300_000_000_000L) .setServerless(Boolean.TRUE));Manual stop blocks wake
Section titled “Manual stop blocks wake”Stopping the sandbox through the API is treated as an operator decision - wake_armed is cleared and exposed endpoints fail until the sandbox is explicitly started again. Only lifecycle-driven stops (idle timer, age, involuntary container exit) re-arm wake. Use this to take a serverless sandbox out of rotation without destroying it.