DockerSandbox
Executes commands inside Docker containers on the local machine. Uses long-lived containers with docker exec for command execution. Targets local development, CI/CD, air-gapped deployments, and cost-sensitive scenarios where cloud sandboxes are unnecessary.
For interface details, see WorkspaceSandbox interface.
InstallationDirect link to Installation
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/docker
pnpm add @mastra/docker
yarn add @mastra/docker
bun add @mastra/docker
Requires Docker Engine running on the host machine.
UsageDirect link to Usage
Add a DockerSandbox to a workspace and assign it to an agent:
import { Agent } from '@mastra/core/agent'
import { Workspace } from '@mastra/core/workspace'
import { DockerSandbox } from '@mastra/docker'
const workspace = new Workspace({
sandbox: new DockerSandbox({
image: 'node:22-slim',
}),
})
const agent = new Agent({
name: 'dev-agent',
model: 'anthropic/claude-opus-4-7',
workspace,
})
Constructor parametersDirect link to Constructor parameters
id?:
name?:
image?:
command?:
env?:
volumes?:
network?:
privileged?:
memory?:
memorySwap?:
cpuQuota?:
cpuPeriod?:
pidsLimit?:
readonlyRootfs?:
capDrop?:
capAdd?:
securityOpt?:
ulimits?:
tmpfs?:
workingDir?:
labels?:
timeout?:
dockerOptions?:
instructions?:
PropertiesDirect link to Properties
id:
name:
provider:
status:
container:
processes:
Background processesDirect link to Background processes
DockerSandbox includes a built-in process manager for spawning and managing background processes. Processes run inside the container using docker exec.
const sandbox = new DockerSandbox({ id: 'dev-sandbox' })
await sandbox._start()
// Spawn a background process
const handle = await sandbox.processes.spawn('node server.js', {
env: { PORT: '3000' },
onStdout: data => console.log(data),
})
// Interact with the process
console.log(handle.stdout)
await handle.sendStdin('input\n')
await handle.kill()
See SandboxProcessManager reference for the full API.
Environment variablesDirect link to Environment variables
Set environment variables at the container level with env. Per-command environment variables can also be passed when spawning processes:
const sandbox = new DockerSandbox({
image: 'node:22-slim',
env: {
NODE_ENV: 'production',
DATABASE_URL: 'postgres://localhost:5432/mydb',
},
})
Bind mountsDirect link to Bind mounts
Mount host directories into the container using the volumes option:
const sandbox = new DockerSandbox({
image: 'node:22-slim',
volumes: {
'/my/project': '/workspace/project',
'/shared/data': '/data',
},
})
Bind mounts are applied at container creation time. The host paths must exist before the sandbox starts.
HardeningDirect link to Hardening
Use Docker-specific resource and hardening options to limit a sandbox container. The following example caps memory and process count, limits CPU to a single core with matching cpuPeriod and cpuQuota values, drops Linux capabilities, makes the root filesystem read-only, and mounts /tmp as writable scratch space:
const sandbox = new DockerSandbox({
image: 'node:22-slim',
memory: 512 * 1024 * 1024,
memorySwap: 512 * 1024 * 1024,
cpuPeriod: 100_000,
cpuQuota: 100_000,
pidsLimit: 256,
readonlyRootfs: true,
capDrop: ['ALL'],
capAdd: ['NET_BIND_SERVICE'],
securityOpt: ['no-new-privileges:true'],
ulimits: [{ name: 'nofile', soft: 1024, hard: 2048 }],
tmpfs: {
'/tmp': 'rw,noexec,nosuid,size=64m',
},
})
These options map directly to Docker HostConfig fields and aren't set unless you pass them.
Review these trade-offs before enabling hardening:
readonlyRootfs: In-container package installs and tools that write outside mounted paths can fail. Addtmpfsentries for writable scratch paths such as/tmp, and mount tmpfs or volumes for package-manager caches such as~/.npmwhen needed.capDrop: Dropping all capabilities disables commands that need Linux capabilities, includingping, mount operations, and FUSE-backed tools. Add back only the capabilities your workload needs.memory: Docker treats0as unlimited. Omitmemoryor pass0only when you don't want a memory cap.memorySwap: Docker memory and swap behavior depends on the host and Docker daemon configuration. When you setmemorywithoutmemorySwap, Docker allows swap up to twice the memory limit by default. SetmemorySwapequal tomemorywhen you want to disable swap for the container; Docker also accepts-1for unlimited swap.pidsLimit: Very low values can breakdocker execworkloads because each command starts additional processes inside the long-lived container.privileged: Privileged containers bypass capability and security-option controls. Don't combineprivileged: truewith capability or security options unless the workload requires it.- Reconnection:
DockerSandboxreuses an existing container when the sandbox ID matches and warns if inspectedHostConfighardening values differ. Destroy and recreate the sandbox to apply changed hardening options. Docker can normalize inspected values, and changingmemorySwapon reconnect can trigger a warning if the original container used Docker's default swap behavior. - Docker Desktop: Resource limits apply inside the Docker Desktop virtual machine on macOS and Windows, so the VM's allocated resources can cap what containers receive.
ReconnectionDirect link to Reconnection
DockerSandbox can reconnect to existing containers by matching labels. When start() is called, it checks for a container with the mastra.sandbox.id label matching the sandbox ID. If found:
- A running container is reused directly.
- A stopped container is restarted.
// First run — creates a new container
const sandbox = new DockerSandbox({ id: 'persistent-sandbox' })
await sandbox._start()
// Later — reconnects to the existing container
const sandbox2 = new DockerSandbox({ id: 'persistent-sandbox' })
await sandbox2._start()
Docker connection optionsDirect link to Docker connection options
Connect to remote Docker hosts or use custom socket paths via dockerOptions:
// Remote Docker host
const sandbox = new DockerSandbox({
dockerOptions: {
host: '192.168.1.100',
port: 2376,
ca: fs.readFileSync('ca.pem'),
cert: fs.readFileSync('cert.pem'),
key: fs.readFileSync('key.pem'),
},
})
// Custom socket path
const sandbox = new DockerSandbox({
dockerOptions: {
socketPath: '/var/run/docker.sock',
},
})