Modal
Executes commands in isolated Modal cloud sandboxes. Provides secure, ephemeral environments backed by Modal's infrastructure. For interface details, see WorkspaceSandbox interface.
InstallationDirect link to Installation
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/modal
pnpm add @mastra/modal
yarn add @mastra/modal
bun add @mastra/modal
UsageDirect link to Usage
Add a ModalSandbox to a workspace and assign it to an agent:
import { Agent } from '@mastra/core/agent'
import { Workspace } from '@mastra/core/workspace'
import { ModalSandbox } from '@mastra/modal'
const workspace = new Workspace({
sandbox: new ModalSandbox({
id: 'dev-sandbox',
baseImage: 'ubuntu:22.04',
timeoutMs: 60_000,
}),
})
const agent = new Agent({
id: 'dev-agent',
model: 'anthropic/claude-opus-4-7',
workspace,
})
AuthenticationDirect link to Authentication
Set Modal credentials via environment variables or constructor options:
MODAL_TOKEN_ID=ak-...
MODAL_TOKEN_SECRET=as-...
Or pass them directly:
const sandbox = new ModalSandbox({
tokenId: process.env.MODAL_TOKEN_ID,
tokenSecret: process.env.MODAL_TOKEN_SECRET,
})
Get your credentials from the Modal dashboard.
Constructor parametersDirect link to Constructor parameters
id?:
appName?:
baseImage?:
timeoutMs?:
env?:
workingDirectory?:
cwd is given. A per-command cwd always wins.workdir?:
workingDirectory. When both are set, workingDirectory wins.tokenId?:
tokenSecret?:
instructions?:
onStart?:
volumes?:
onStop?:
onDestroy?:
PropertiesDirect link to Properties
id:
name:
provider:
status:
modal:
processes:
Sandbox lifecycleDirect link to Sandbox lifecycle
_start(): Attempts to reconnect to an existing running sandbox. If none is found, creates a sandbox from the latest snapshot (if available from a previous_stop()), or from the baseImage._stop(): Snapshots the filesystem, then terminates the sandbox. Snapshot is kept in memory on the same instance for future starts._destroy(): Terminates the sandbox and discards any snapshot.
const sandbox = new ModalSandbox({
id: 'dev-sandbox',
baseImage: 'ubuntu:22.04',
timeoutMs: 300_000,
})
await sandbox._start()
await sandbox.processes.spawn('npm install')
await sandbox._stop()
await sandbox._start()
Volumes and persistent filesDirect link to Volumes and persistent files
Mount Modal Volumes with the volumes option, then use ModalFilesystem to expose a mounted path to the agent's workspace file tools. Files written under the mount persist across sandbox restarts.
import { Workspace } from '@mastra/core/workspace'
import { ModalFilesystem, ModalSandbox } from '@mastra/modal'
import { ModalClient } from 'modal'
const modal = new ModalClient()
const privateVolume = await modal.volumes.fromName('agent-user-123', { createIfMissing: true })
const teamVolume = await modal.volumes.fromName('agent-team', { createIfMissing: true })
const sandbox = new ModalSandbox({
id: 'agent-sandbox',
workingDirectory: '/workspace',
volumes: {
'/mnt/agent': privateVolume,
'/mnt/team': teamVolume,
},
})
const workspace = new Workspace({
sandbox,
filesystem: new ModalFilesystem({ sandbox, basePath: '/mnt/agent' }),
})
ModalFilesystem runs file operations inside the sandbox and confines all paths to basePath. Set readOnly: true to reject writes.
Writes made by other sandboxes to the same Volume are only visible after a reload. Call reloadVolumes() on a long-lived sandbox to pick them up:
await sandbox.reloadVolumes()
Keep the working directory outside every Volume mount (for example /workspace). Modal can't reload a Volume that is the current working directory, so ModalSandbox throws if workingDirectory is at or inside a mount path.
Background processesDirect link to Background processes
ModalSandbox includes a built-in process manager for spawning and managing background processes. Each spawn() call creates a new ContainerProcess via the Modal SDK's Sandbox.exec() API.
const sandbox = new ModalSandbox({ id: 'dev-sandbox' })
await sandbox._start()
// Spawn a background process
const handle = await sandbox.processes.spawn('node script.js', {
env: { PORT: '3000' },
onStdout: data => console.log(data),
})
// Wait for the process to complete
const result = await handle.wait()
console.log(result.exitCode)
// Kill the process
await handle.kill()
sendStdin() isn't supported. The Modal JS SDK doesn't expose stdin on Sandbox.exec().
See SandboxProcessManager reference for the full API.