Managed lifecycle
Coordinate Sandbox creation, commands, and cleanup as durable steps in a function run.
Access-gated beta. The low-level TypeScript API below follows the access-gated Sandbox beta. The planned
step.sandbox.typescripthelper has no published call shape yet.
Use durable Sandbox steps when isolated code belongs to a longer function run. Inngest records each operation’s result, so a resumed function can continue after completed steps. The API you choose determines which lifecycle and cleanup actions your function must handle.
| API | What Inngest handles | What you handle |
|---|---|---|
step.sandbox.create() and other low-level steps | Durable operation results, safe retries, readiness polling by default, and step failures | When to pause, resume, snapshot, clone, and destroy the Sandbox; cleanup after permanent failure |
inngest.sandboxes | Immediate Sandbox requests and bounded readiness polling | Retries, cancellation, and cleanup in your server process |
Planned step.sandbox.typescript | Starts a Sandbox, runs TypeScript, and stops the Sandbox in one call | Planned; no beta API |
Use a Sandbox in a durable function
Add the Sandbox middleware to a TypeScript v4 client. Each step.sandbox operation takes a stable step ID. This example creates a Sandbox, runs a command, and destroys the Sandbox on the successful path.
import { Inngest } from "inngest";
import { sandboxMiddleware } from "inngest/experimental";
const inngest = new Inngest({
id: "sandbox-lifecycle",
middleware: [sandboxMiddleware()],
});
export const runInSandbox = inngest.createFunction(
{
id: "run-in-sandbox",
triggers: { event: "sandbox/job.requested" },
},
async ({ event, step }) => {
const sandbox = await step.sandbox.create("create-sandbox", {
name: `job-${event.data.jobId}`,
vcpu: 1,
memoryMb: 1024,
runningTimeout: "60s",
});
const result = await sandbox.commands.run(
"run-command",
["node", "-e", "console.log('done')"],
{ timeout: "30s" },
);
await sandbox.destroy("destroy-sandbox");
return { exitCode: result.exitCode, stdout: result.stdout };
},
);
Use a stable, Sandbox-safe job ID in the event. A completed step replays its result, including the Sandbox object returned by Create. This avoids creating another Sandbox when the function resumes after a later step. It does not keep the guest process or filesystem alive if the Sandbox itself is lost.
Create waits for RUNNING by default. If readiness times out, the Sandbox may still exist. When cleanup needs an ID even if readiness fails, create with runningTimeout: false, then call sandbox.waitUntilRunning("wait-for-sandbox", { timeout: "60s" }) as a separate step.
Clean up after failure
The example's Destroy step runs only if execution reaches it. If the function fails after all retries, use an onFailure handler or a separate cleanup function that can retrieve the Sandbox ID. Store the ID somewhere that handler can read after Create. The failure handler runs as a separate function; a JavaScript finally block in the main function does not replace this cleanup path.
For immediate server-side calls through inngest.sandboxes, use try/finally and call sandbox?.destroy() in finally. The direct client has no durable step replay.
Destroy removes the Sandbox filesystem, processes, and retained process output. Persist artifacts outside the Sandbox before destroying it. Destroy may first return TERMINATING; teardown continues after the API accepts the request.
Pause, resume, and reuse state
Pause releases the live runtime into a private checkpoint. Resume returns the same Sandbox ID with its filesystem, memory, and remaining runtime. The current beta allows one hour of active runtime per Sandbox; time spent paused does not consume it. Use the returned running Sandbox before making another command, file, log, or process call.
A user snapshot keeps a copy of memory, disk, environment, image, and resource settings while the source Sandbox continues running. Clone creates a new Sandbox ID from a ready snapshot. Snapshot creation and readiness are separate phases. A wait timeout does not cancel the snapshot being created.
The Sandbox filesystem persists through pause and resume, and a snapshot clone receives the captured filesystem. S3-backed persistent filesystem mounts can share a backing path across different Sandboxes, including clones; those mounts are a separate storage choice from the Sandbox’s private filesystem.
Retries and uncertain outcomes
Let unexpected step.sandbox errors escape the function. Inngest retries operations the middleware marks safe and records a failure when retries are exhausted or an operation is unsafe to repeat. An operation_ambiguous error means a command, process start, or signal may have happened without a confirmed response. Inspect the Sandbox or the operation's external effect before deciding whether to repeat it.
A durable step records the operation result; it does not promise that a Sandbox, guest process, or retained output survives a lost runtime. Inspect the current Sandbox state with Get when work resumes after a long wait or external interruption.
Sandbox operations used as durable steps appear with the function's other steps in its run trace.
One-call TypeScript execution
A planned step.sandbox.typescript call will start a Sandbox, run TypeScript, and stop it automatically. This planned path is for one isolated task that does not keep a Sandbox between steps.
This page describes isolated microVM Sandboxes. Deployment preview environments are called branch deploys.