Agents use sandboxes for reading and writing files, running shell commands, spawning background processes, or operating a real computer. Sandbox lifecycles are typically managed by agents: they start them up on the first tool call, keep them running across requests, and shut them down when they're done.
Now Mastra's APIs give you fine-grained control over the sandbox lifecycle. You can create, mount a filesystem, snapshot, pause, re-start, and destroy entirely. You can also define lifecycle hooks like onStop to trigger other actions, or inspect or kill specific processes on the sandbox.
Lifecycle control
The main Mastra instance is the parent of every registered workspace and handles process-level shutdown:
await mastra.shutdown();mastra.shutdown(): Callsstop()on every registered workspace.
Workspaces are parents to child sandboxes and have three methods of their own:
await workspace.init();
await workspace.stop();
await workspace.destroy();workspace.init(): Pre-starts the workspace and any child sandboxes.workspace.stop(): Suspends live resources without destroying them.workspace.destroy(): Closes all workspace-owned resources and clears cached sandbox references.
Clear the workspace cache so the next build is fresh:
workspace.clearSandboxCache("cache-123");workspace.clearSandboxCache(cacheKey): Synchronous return to clear a cached sandbox.
Sandboxes can also be controlled individually:
await sandbox.start();
await sandbox.stop();
await sandbox.destroy();sandbox.start(): Starts a sandbox, or reconnects to an existing one.sandbox.stop(): Suspends a sandbox without destroying it.sandbox.destroy(): Destroys a sandbox and cleans up its provider resources.
Lifecycle status
Each sandbox has a status with resources used:
await sandbox.getInfo();status: One ofstarting,running,stopped, orerror.resources: Current memory (memoryMB) and CPU (cpuPercent) usage from the sandbox provider.
Lifecycle hooks
Hooks are passed as constructor options:
import { E2BSandbox } from "@mastra/e2b";
const sandbox = new E2BSandbox({
id: "demo-sandbox",
apiKey: process.env.E2B_API_KEY,
onStart: ({ sandbox, outcome }) => {
console.log(`Started ${sandbox.id} ${outcome}`);
},
onStop: ({ sandbox }) => {},
onDestroy: ({ sandbox }) => {}
});onStart: Fires when the sandbox starts. Receives:sandbox: The sandbox instance.outcome: One ofcreatedorconnected.
onStop: Fires when the sandbox stops. Receives:sandbox: The sandbox instance.
onDestroy: Fires when the sandbox is destroyed. Receives:sandbox: The sandbox instance.
Persistence
Persistence is provider-specific — some reconnect by sandbox id, some preserve snapshots and volumes, others create a fresh environment every time. Sandboxes expose three ways to persist state:
Save the sandbox's current state where the provider supports it:
await sandbox.snapshot();sandbox.snapshot(): Persists the current sandbox state.
Set env vars that survive provider pause and resume:
sandbox.setEnv(() => {
return { API_KEY: process.env.API_KEY };
});sandbox.setEnv(): Sets env vars for every command routed through the sandbox. Synchronous return.
Mount an external filesystem to persist files:
await sandbox.mount(new S3Filesystem({ bucket: "..." }), "/workspace");sandbox.mount(filesystem, path): Mounts a filesystem at a sandbox directory.
Background processes
Background processes running in the sandbox have their own lifecycle.
The sandbox exposes methods to spawn, list, and kill processes:
const handle = await sandbox.processes.spawn("node server.js", {
env: { PORT: "3000" }
});
await sandbox.processes.list();
await sandbox.processes.kill(handle.pid);sandbox.processes.spawn(command, options): Starts a background process. Returns a handle withpid.sandbox.processes.list(): Lists running background processes.sandbox.processes.kill(pid): Kills a running process bypid.
Background processes fire three hooks, configured on the workspace's tool config:
import { WORKSPACE_TOOLS, Workspace } from "@mastra/core/workspace";
import { E2BSandbox } from "@mastra/e2b";
new Workspace({
sandbox: new E2BSandbox({ id: "demo-sandbox", apiKey: process.env.E2B_API_KEY }),
tools: {
[WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND]: {
backgroundProcesses: {
onStdout: (data, { pid }) => {
console.log(`onStdout ${pid} ${data}`);
},
onStderr: (data, { pid }) => {},
onExit: ({ pid, exitCode }) => {}
}
}
}
});onStdout: Fires on stdout data. Receives:data: The stdout output.pid: The process id.
onStderr: Fires on stderr data. Receives:data: The stderr output.pid: The process id.
onExit: Fires when the process exits. Receives:pid: The process id.exitCode: The exit code.
Network safety
Network defaults and controls vary by sandbox provider:
Reach a sandbox-internal port from outside:
sandbox.networking?.getPortUrl(8000);sandbox.networking.getPortUrl(port): Returns a URL for the given sandbox port.
Control outbound network access per sandbox:
new LocalSandbox({ workingDirectory: "./workspace", allowNetwork: true });allowNetwork: Enables outbound network access.
For more information and full configuration options, see:
