Daytona
Executes commands in isolated Daytona cloud sandboxes. Supports multiple runtimes, resource configuration, volumes, snapshots, streaming output, sandbox reconnection, filesystem mounting (S3, GCS), and network isolation. For interface details, see WorkspaceSandbox interface.
InstallationInstallation的直接链接
- npm
- pnpm
- Yarn
- Bun
npm install @mastra/daytona
pnpm add @mastra/daytona
yarn add @mastra/daytona
bun add @mastra/daytona
Set your Daytona API key in one of three ways.
- Shell export
- .env file
- Constructor
export DAYTONA_API_KEY=your-api-key
DAYTONA_API_KEY=your-api-key
new DaytonaSandbox({ apiKey: 'your-api-key' })
UsageUsage的直接链接
Add a DaytonaSandbox to a workspace and assign it to an agent:
import { Agent } from '@mastra/core/agent'
import { Workspace } from '@mastra/core/workspace'
import { DaytonaSandbox } from '@mastra/daytona'
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
language: 'typescript',
timeout: 120_000,
}),
})
const agent = new Agent({
id: 'code-agent',
name: 'Code Agent',
instructions: 'You are a coding assistant working in this workspace.',
model: 'anthropic/claude-sonnet-4-6',
workspace,
})
const response = await agent.generate(
'Print "Hello, world!" and show the current working directory.',
)
console.log(response.text)
// I'll run both commands simultaneously!
//
// Here are the results:
//
// 1. **Hello, world!** — Successfully printed the message.
// 2. **Current Working Directory** — `/home/daytona`
//
// Both commands ran in parallel and completed successfully!
With a snapshotWith a snapshot的直接链接
Use a pre-built snapshot to skip environment setup time:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
snapshot: 'my-snapshot-id',
timeout: 60_000,
}),
})
Custom image with resourcesCustom image with resources的直接链接
Use a custom Docker image with specific resource allocation:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
image: 'node:20-slim',
resources: { cpu: 2, memory: 4, disk: 6 },
language: 'typescript',
}),
})
Ephemeral sandboxEphemeral sandbox的直接链接
For one-shot tasks: sandbox is deleted immediately on stop:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
ephemeral: true,
language: 'python',
}),
})
Streaming outputStreaming output的直接链接
Stream command output in real time via onStdout and onStderr callbacks:
await sandbox.executeCommand('bash', ['-c', 'for i in 1 2 3; do echo "line $i"; sleep 1; done'], {
onStdout: chunk => process.stdout.write(chunk),
onStderr: chunk => process.stderr.write(chunk),
})
Both callbacks are optional and can be used independently.
ReconnectionReconnection的直接链接
Reconnect to an existing sandbox by providing the same id. The sandbox resumes with its files and state intact:
const sandbox = new DaytonaSandbox({ id: 'my-persistent-sandbox' })
// First session
await sandbox._start()
await sandbox.executeCommand('sh', ['-c', 'echo "session 1" > /tmp/state.txt'])
await sandbox._stop()
// Later — reconnects to the same sandbox
const sandbox2 = new DaytonaSandbox({ id: 'my-persistent-sandbox' })
await sandbox2._start()
const result = await sandbox2.executeCommand('cat', ['/tmp/state.txt'])
console.log(result.stdout) // "session 1"
If the sandbox is in a stopped or archived state, it's restarted automatically. If it's in a dead state (destroyed, errored), a fresh sandbox is created instead.
Filesystem mountingFilesystem mounting的直接链接
Mount S3 or GCS buckets as local directories inside the sandbox.
Via workspace mounts configVia workspace mounts config的直接链接
The simplest way: filesystems are mounted automatically when the sandbox starts:
import { Workspace } from '@mastra/core/workspace'
import { DaytonaSandbox } from '@mastra/daytona'
import { GCSFilesystem } from '@mastra/gcs'
import { S3Filesystem } from '@mastra/s3'
const workspace = new Workspace({
mounts: {
'/s3-data': new S3Filesystem({
bucket: process.env.S3_BUCKET!,
region: 'auto',
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
endpoint: process.env.S3_ENDPOINT, // e.g. https://<account-id>.r2.cloudflarestorage.com
}),
'/gcs-data': new GCSFilesystem({
bucket: process.env.GCS_BUCKET!,
projectId: 'my-project-id',
credentials: JSON.parse(process.env.GCS_SERVICE_ACCOUNT_KEY!),
}),
},
sandbox: new DaytonaSandbox({ language: 'python' }),
})
When the workspace starts, the filesystems are automatically mounted at the specified paths. Code running in the sandbox can then access files at /s3-data and /gcs-data as if they were local directories.
Temporary S3 credentialsTemporary S3 credentials的直接链接
Pass all three credential values to S3Filesystem when using temporary credentials. Daytona forwards the session token to s3fs:
import { Workspace } from '@mastra/core/workspace'
import { DaytonaSandbox } from '@mastra/daytona'
import { S3Filesystem } from '@mastra/s3'
const workspace = new Workspace({
mounts: {
'/s3-data': new S3Filesystem({
bucket: process.env.S3_BUCKET!,
region: process.env.S3_REGION ?? 'us-east-1',
endpoint: process.env.S3_ENDPOINT,
prefix: 'resource-123/thread-456/',
accessKeyId: process.env.SCOPED_S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.SCOPED_S3_SECRET_ACCESS_KEY!,
sessionToken: process.env.SCOPED_S3_SESSION_TOKEN!,
}),
},
sandbox: new DaytonaSandbox({ language: 'python', ephemeral: true }),
})
Before starting the workspace, obtain credentials from your storage provider that authorize only the intended prefix. Credential issuance is provider-specific; Mastra doesn't mint or restrict credentials. A prefix selects a directory but doesn't enforce authorization. Authenticate each request, authorize its resource and thread, and use separate sandboxes for separate security scopes.
Temporary credentials are loaded when the mount starts and aren't automatically refreshed. Host-side credential provider functions don't refresh the mount. Keep runs within the credential lifetime and create a new sandbox with fresh credentials for later runs. Reconnecting to a sandbox doesn't renew its credentials.
Credentials are uploaded into owner-only files inside private directories. After launching s3fs, Daytona removes the temporary-credential staging file and directory. The daemon retains the credentials in its environment, which sandbox code running as the same user or root can still read. Never supply broader credentials than the sandbox needs. Mounts using long-lived credentials retain their password files while s3fs needs them. Unmount and reconnect cleanup remove those files after verifying that the daemon has exited. If a daemon is still active, including after a mount is moved aside, or its status can't be checked, the files are retained and a warning is logged. Cleanup on a later unmount of the same path retries removal; deleting the sandbox removes any remaining files.
Prefixed filesystems require permission to list their prefix during initialization. With s3fs, a prefixed mount may also require a zero-byte object at the exact <prefix>/ key. Provision that directory marker before mounting. After launching s3fs, Daytona checks the mounted directory's metadata without listing its contents, with a 15-second timeout and forced termination after another 5 seconds. A failed check reports a mount failure. Cleanup attempts to unmount the failed mount, moving a stuck mount aside if necessary to free the original path for retry. Moved stale mounts may remain until sandbox deletion. This startup check doesn't guarantee read or write access to individual files or ongoing daemon health; verify a read and write through the mounted path.
Via sandbox.mount()via-sandboxmount的直接链接
Mount manually at any point after the sandbox has started:
S3S3的直接链接
import { S3Filesystem } from '@mastra/s3'
await sandbox.mount(
new S3Filesystem({
bucket: process.env.S3_BUCKET!,
region: 'us-east-1',
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
}),
'/data',
)
S3-compatible (Cloudflare R2, MinIO)S3-compatible (Cloudflare R2, MinIO)的直接链接
import { S3Filesystem } from '@mastra/s3'
await sandbox.mount(
new S3Filesystem({
bucket: process.env.S3_BUCKET!,
region: 'auto',
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
endpoint: process.env.S3_ENDPOINT, // e.g. https://<account-id>.r2.cloudflarestorage.com
}),
'/data',
)
GCSGCS的直接链接
import { GCSFilesystem } from '@mastra/gcs'
await sandbox.mount(
new GCSFilesystem({
bucket: process.env.GCS_BUCKET!,
projectId: 'my-project-id',
credentials: JSON.parse(process.env.GCS_SERVICE_ACCOUNT_KEY!),
}),
'/data',
)
Network isolationNetwork isolation的直接链接
Restrict outbound network access:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
networkBlockAll: true,
networkAllowList: '10.0.0.0/8,192.168.0.0/16',
}),
})
Use domainAllowList for services whose IP addresses change, such as package registries and hosted APIs:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
networkBlockAll: true,
domainAllowList: 'registry.npmjs.org,*.githubusercontent.com',
}),
})
Both allow lists are applied at sandbox creation and are preserved by clone(). To change the policy after the sandbox has started, use the underlying Daytona sandbox:
await sandbox.instance.updateNetworkSettings({
domainAllowList: 'api.example.com',
})
SecretsSecrets的直接链接
Inject credentials without exposing raw values to code running inside the sandbox. Create a Daytona Secret once for your organization (via the Daytona dashboard or SDK), then map environment variable names to Secret names:
const workspace = new Workspace({
sandbox: new DaytonaSandbox({
secrets: {
GITHUB_TOKEN: 'github-token',
},
}),
})
Inside the sandbox, the environment variable holds an opaque placeholder. Daytona's egress proxy substitutes the real value into HTTPS request headers toward the Secret's allowed hosts, so the raw credential never enters the sandbox. Secrets are applied at sandbox creation and are preserved by clone().
Computer use (desktop)Computer use (desktop)的直接链接
Enable the computer capability with computerUse. This adds screenshot, mouse, and keyboard control to the sandbox. When the sandbox is used in a workspace, agents automatically get the mastra_workspace_computer_* tools.
Computer use is disabled by default. Set computerUse: true to start the desktop processes (Xvfb, xfce4, x11vnc, noVNC) lazily on the first computer operation:
const sandbox = new DaytonaSandbox({ computerUse: true })
await sandbox.start()
await sandbox.computer.leftClick(100, 200)
await sandbox.computer.type('hello')
const { data } = await sandbox.computer.screenshot() // PNG bytes
// Live desktop view via the noVNC preview link
const url = await sandbox.computer.streamUrl()
Pass an options object to configure the capability. For example, disable automatic desktop startup when you manage the Daytona process directly:
const sandbox = new DaytonaSandbox({
computerUse: { autoStart: false },
})
await sandbox.start()
await sandbox.daytona.computerUse.start()
For Daytona-specific desktop APIs (regions, compressed screenshots, screen recording, accessibility tree), use the direct SDK access escape hatch: sandbox.daytona.computerUse.
Constructor parametersConstructor parameters的直接链接
id?:
apiKey?:
apiUrl?:
target?:
timeout?:
language?:
snapshot?:
image?:
resources?:
env?:
workingDirectory?:
cwd is given. A per-command cwd always wins. When set, the sandbox skips its automatic working-directory probe; when omitted, the probe fills the workingDirectory getter after start.labels?:
name?:
user?:
public?:
ephemeral?:
autoStopInterval?:
autoArchiveInterval?:
autoDeleteInterval?:
volumes?:
networkBlockAll?:
networkAllowList?:
domainAllowList?:
*.githubusercontent.com. Use this instead of networkAllowList for services whose IP addresses change.secrets?:
computerUse?:
PropertiesProperties的直接链接
id:
name:
provider:
status:
instance:
processes:
computer:
Background processesBackground processes的直接链接
DaytonaSandbox includes a built-in process manager for spawning and managing background processes. Processes run in the Daytona cloud sandbox using session-based command execution.
const sandbox = new DaytonaSandbox({ language: 'typescript' })
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.
Mounting cloud storageMounting cloud storage的直接链接
Daytona sandboxes can mount S3 or GCS buckets, making cloud storage accessible as local directories inside the sandbox. This is useful for:
- Processing large datasets stored in cloud buckets
- Writing output files directly to cloud storage
- Sharing data between sandbox sessions
For usage examples, see Filesystem mounting.
Daytona sandboxes use FUSE (Filesystem in Userspace) to mount cloud storage:
The required FUSE tools are installed automatically at mount time if not already present in the sandbox image.
S3 environment variablesS3 environment variables的直接链接
| Variable | Description |
|---|---|
S3_BUCKET | Bucket name |
S3_REGION | AWS region or auto for R2/MinIO |
S3_ACCESS_KEY_ID | Access key ID |
S3_SECRET_ACCESS_KEY | Secret access key |
S3_ENDPOINT | Endpoint URL (S3-compatible only) |
GCS environment variablesGCS environment variables的直接链接
| Variable | Description |
|---|---|
GCS_BUCKET | Bucket name |
GCS_SERVICE_ACCOUNT_KEY | Service account key JSON (full JSON string, not a path) |
Reducing cold start latency with a snapshotReducing cold start latency with a snapshot的直接链接
By default, s3fs and gcsfuse are installed at first mount via apt, which adds startup time. To eliminate this, prebake them into a Daytona snapshot and pass the snapshot name via the snapshot option.
Option 1: Declarative image build
import { Daytona, Image } from '@daytonaio/sdk'
const template = Image.base('daytonaio/sandbox')
.runCommands('sudo apt-get update -qq')
.runCommands('sudo apt-get install -y s3fs')
// gcsfuse requires the Google Cloud apt repository
.runCommands(
'sudo mkdir -p /etc/apt/keyrings && ' +
'curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg -o /tmp/gcsfuse-key.gpg && ' +
'sudo gpg --batch --yes --dearmor -o /etc/apt/keyrings/gcsfuse.gpg /tmp/gcsfuse-key.gpg && ' +
// Use gcsfuse-jammy for Ubuntu, gcsfuse-bookworm for Debian
'echo "deb [signed-by=/etc/apt/keyrings/gcsfuse.gpg] https://packages.cloud.google.com/apt gcsfuse-jammy main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list',
)
.runCommands('sudo apt-get update -qq && sudo apt-get install -y gcsfuse')
const daytona = new Daytona()
await daytona.snapshot.create(
{
name: 'cloud-fs-mounting',
image: template,
},
{ onLogs: console.log },
)
Option 2: Dockerfile: Use Image.fromDockerfile()
FROM daytonaio/sandbox
RUN sudo apt-get update -qq
RUN sudo apt-get install -y s3fs
# Use gcsfuse-jammy for Ubuntu, gcsfuse-bookworm for Debian
RUN sudo mkdir -p /etc/apt/keyrings && curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg -o /tmp/gcsfuse-key.gpg && sudo gpg --batch --yes --dearmor -o /etc/apt/keyrings/gcsfuse.gpg /tmp/gcsfuse-key.gpg && echo "deb [signed-by=/etc/apt/keyrings/gcsfuse.gpg] https://packages.cloud.google.com/apt gcsfuse-jammy main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
RUN sudo apt-get update -qq && sudo apt-get install -y gcsfuse
import { Daytona, Image } from '@daytonaio/sdk'
const daytona = new Daytona()
await daytona.snapshot.create(
{
name: 'cloud-fs-mounting',
image: Image.fromDockerfile('./Dockerfile'),
},
{ onLogs: console.log },
)
Then use the snapshot name in your sandbox config:
const workspace = new Workspace({
mounts: {
'/s3-data': new S3Filesystem({/* ... */}),
'/gcs-data': new GCSFilesystem({/* ... */}),
},
sandbox: new DaytonaSandbox({ snapshot: 'cloud-fs-mounting' }),
})
Direct SDK accessDirect SDK access的直接链接
Access the underlying Daytona Sandbox instance for filesystem, git, and other operations not exposed through the WorkspaceSandbox interface:
const daytonaSandbox = sandbox.instance
// Upload a file
await daytonaSandbox.fs.uploadFile(Buffer.from('hello'), '/tmp/hello.txt')
// Run git operations
await daytonaSandbox.git.clone('https://github.com/org/repo', '/workspace/repo')
The instance getter throws SandboxNotReadyError if the sandbox hasn't been started yet.
Sandbox creation modesSandbox creation modes的直接链接
DaytonaSandbox selects a creation mode based on the options provided:
| Options | Creation mode |
|---|---|
snapshot set | Snapshot-based (snapshot takes precedence over image) |
image set (no snapshot) | Image-based (optionally with resources) |
| Neither set | Default snapshot-based |
Resources are only applied when image is set. Passing resources without image has no effect.