Daytona is a cloud development sandbox platform that creates isolated, on-demand environments for running code, automating GUI interactions, managing files, and integrating with AI agents. It provides multi-language SDKs (Python, TypeScript, Go, Java, Ruby), a full-featured CLI, and an MCP server for LLM tool integration. Sandboxes spin up in seconds, run any Docker image, and support features like code interpretation, computer use (VNC-based GUI automation), Git operations, LSP intelligence, PTY sessions, snapshots, and persistent volumes.
1. Quick Start
1.1 Create Your First Sandbox (Python)
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.create()
response = sandbox.process.exec("echo 'Hello from Daytona!'")
print(response.result)
# Output: Hello from Daytona!
daytona.delete(sandbox)
1.2 Create Your First Sandbox (TypeScript)
import { Daytona } from '@daytona/sdk'
async function main() {
const daytona = new Daytona()
const sandbox = await daytona.create()
const response = await sandbox.process.executeCommand('echo "Hello from Daytona!"')
console.log(response.result)
// Output: Hello from Daytona!
await sandbox.delete()
}
main().catch(console.error)
1.3 Create Your First Sandbox (CLI)
# Authenticate
daytona login
# Create a sandbox
daytona create
# List your sandboxes
daytona list
Note
Before using any SDK, set the
DAYTONA_API_KEYenvironment variable. You can generate an API key from the Daytona dashboard. For the CLI, rundaytona loginto authenticate via browser.
1.4 Run Python Code in a Sandbox
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.create()
result = sandbox.code_interpreter.run_code("print('2 + 2 =', 2 + 2)")
print(result.stdout)
# Output: 2 + 2 = 4
daytona.delete(sandbox)
2. Installation
2.1 Python SDK
Requirements: Python 3.9 or later.
pip install daytona
The package is also published under the alias daytona_sdk:
pip install daytona_sdk
2.2 TypeScript SDK
Requirements: Node.js 18 or later.
npm install @daytona/sdk
Or with yarn:
yarn add @daytona/sdk
2.3 Go SDK
Requirements: Go 1.21 or later.
go get github.com/daytonaio/daytona/libs/sdk-go
2.4 Java SDK
Requirements: Java 11 or later with Maven or Gradle.
Add the dependency to your pom.xml:
<dependency>
<groupId>io.daytona</groupId>
<artifactId>sdk</artifactId>
<version>LATEST</version>
</dependency>
2.5 Ruby SDK
Requirements: Ruby 3.0 or later.
gem install daytona
2.6 CLI Installation
Download the Daytona CLI binary for your platform from the Daytona releases page or install via your package manager. After installation, verify:
daytona version
Expected output:
Daytona CLI version v0.x.x
Tip
Set up shell autocompletion immediately after installing the CLI. Run
daytona autocomplete bash(orzsh,fish,powershell) to enable tab-completion for all commands and flags.
2.7 Shell Autocompletion
The CLI supports autocompletion for bash, zsh, fish, and powershell.
# Bash
daytona autocomplete bash
# Then: source ~/.bashrc
# Zsh
daytona autocomplete zsh
# Then: source ~/.zshrc
# Fish
daytona autocomplete fish
# Then: source ~/.config/fish/config.fish
# PowerShell
daytona autocomplete powershell
# Then: . ~/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1
The completion script is automatically injected into your shell profile. Restart your terminal or source the profile file to activate.
Note
For bash, ensure
bash-completionis installed on your system. See the Daytona docs on autocomplete for platform-specific instructions.
3. Configuration
3.1 SDK Authentication
All SDKs authenticate via API key or JWT token. The simplest approach is to set environment variables:
| Variable | Purpose |
|---|---|
DAYTONA_API_KEY |
API key for authentication (primary method) |
DAYTONA_API_URL |
API endpoint (default: https://app.daytona.io/api) |
DAYTONA_JWT_TOKEN |
JWT token (alternative to API key) |
DAYTONA_ORGANIZATION_ID |
Required when using JWT authentication |
DAYTONA_TARGET |
Target region for sandbox placement |
Python explicit configuration:
from daytona import Daytona, DaytonaConfig
config = DaytonaConfig(
api_key="your-api-key",
api_url="https://app.daytona.io/api", # default
target="us", # optional region
connection_pool_maxsize=250, # default; set None for unlimited
)
daytona = Daytona(config)
TypeScript explicit configuration:
import { Daytona } from '@daytona/sdk'
const daytona = new Daytona({
apiKey: 'your-api-key',
apiUrl: 'https://app.daytona.io/api',
target: 'us',
})
Go explicit configuration:
import "github.com/daytonaio/daytona/libs/sdk-go/pkg/daytona"
client, err := daytona.NewClient(daytona.WithAPIKey("your-api-key"))
Important
The
server_urlconfiguration field is deprecated. Always useapi_urlinstead. If both are provided,api_urltakes precedence.server_urlwill be removed in a future release.
3.2 JWT Authentication
For service-to-service flows, use JWT tokens with an organization ID:
from daytona import Daytona, DaytonaConfig
config = DaytonaConfig(
jwt_token="your-jwt-token",
organization_id="your-organization-id",
)
daytona = Daytona(config)
3.3 CLI Configuration
The CLI stores configuration in a JSON file at:
$DAYTONA_CONFIG_DIR/config.json(ifDAYTONA_CONFIG_DIRis set)$XDG_CONFIG_HOME/daytona/config.json(Linux/macOS default)%APPDATA%/daytona/config.json(Windows default)
The configuration file contains profiles with API URLs and authentication tokens:
{
"activeProfile": "default",
"profiles": [
{
"id": "default",
"name": "Default",
"api": {
"url": "https://app.daytona.io/api",
"key": "dc_your_api_key"
},
"activeOrganizationId": "org-id-here"
}
]
}
Environment variable overrides: Setting both DAYTONA_API_URL and DAYTONA_API_KEY as environment variables bypasses the config file entirely, creating an ephemeral "env" profile.
3.4 CLI Authentication
# Interactive browser-based login (Auth0 OAuth)
daytona login
# Logout and clear stored tokens
daytona logout
The login flow opens your browser for Auth0 authentication, then stores the access and refresh tokens in your CLI config. Tokens are automatically refreshed when they expire.
Auth0 environment variables (for custom identity providers or CI/CD):
| Variable | Purpose |
|---|---|
DAYTONA_AUTH0_DOMAIN |
Auth0 domain |
DAYTONA_AUTH0_CLIENT_ID |
Auth0 client ID |
DAYTONA_AUTH0_CLIENT_SECRET |
Auth0 client secret |
DAYTONA_AUTH0_CALLBACK_PORT |
Local callback port for OAuth redirect |
DAYTONA_AUTH0_AUDIENCE |
Auth0 audience |
3.5 Connection Pool Tuning
The Python SDK defaults to a connection pool of 250 simultaneous HTTP connections. For workloads with many concurrent long-lived operations (PTY sessions, exec sessions, code interpreter), set connection_pool_maxsize=None to remove the limit:
config = DaytonaConfig(
api_key="your-key",
connection_pool_maxsize=None, # unlimited connections
)
4. Core Usage
4.1 Sandbox Lifecycle
Sandboxes follow a defined state machine:
creating --> started <--> stopped --> archived --> destroyed
Additional transient states include: pending_build, building_snapshot, pulling_snapshot, resizing, snapshotting, forking, restoring, starting, stopping, archiving, destroying, error, build_failed, and unknown.
Python lifecycle example:
from daytona import Daytona
daytona = Daytona()
# Create (state: creating -> started)
sandbox = daytona.create()
print(f"Sandbox {sandbox.id} is {sandbox.state}")
# Stop (state: started -> stopped)
sandbox.stop()
# Start again (state: stopped -> started)
sandbox.start()
# Get an existing sandbox by ID
same_sandbox = daytona.get(sandbox.id)
# Delete permanently (state: -> destroyed)
daytona.delete(sandbox)
TypeScript lifecycle example:
import { Daytona } from '@daytona/sdk'
const daytona = new Daytona()
const sandbox = await daytona.create()
console.log(`Sandbox ${sandbox.id} is ${sandbox.state}`)
await sandbox.stop()
await sandbox.start()
const existing = await daytona.get(sandbox.id)
await sandbox.delete()
4.2 Listing Sandboxes
Python:
result = daytona.list()
print(f"Total sandboxes: {result.total}")
for sb in result.items:
print(f" {sb.id} - {sb.state}")
CLI:
# Default table output
daytona list
# JSON output
daytona list -f json
# YAML output
daytona list -f yaml
4.3 Creating Sandboxes from Images
Use CreateSandboxFromImageParams to specify a custom Docker image:
from daytona import Daytona, CreateSandboxFromImageParams
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromImageParams(
image="ubuntu:latest",
language="python",
env_vars={"MY_VAR": "hello"},
auto_stop_interval=30, # minutes; 0 = never
)
)
4.4 Creating Sandboxes from Snapshots
Snapshots are pre-built environments that launch faster than building from an image:
from daytona import Daytona, CreateSandboxFromSnapshotParams
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
snapshot="my-python-snapshot",
language="python",
)
)
4.5 Declarative Image Builder
The Image class provides a fluent, declarative API for building custom sandbox images without writing Dockerfiles manually.
Factory methods:
| Method | Description |
|---|---|
Image.base(image) |
Start from any Docker image |
Image.debian_slim(python_version) |
Debian slim with Python (3.9-3.13) |
Image.from_dockerfile(path) |
Build from an existing Dockerfile |
Supported Python versions: 3.9, 3.10, 3.11, 3.12, 3.13. If no version is specified, the local Python version is matched.
Builder methods (chainable):
| Method | Description |
|---|---|
.pip_install(*packages) |
Install pip packages |
.pip_install_from_requirements(path) |
Install from requirements.txt |
.pip_install_from_pyproject(path, optional_deps) |
Install from pyproject.toml |
.run_commands(*commands) |
Run shell commands |
.env(env_vars) |
Set environment variables |
.workdir(path) |
Set working directory |
.entrypoint(commands) |
Set container entrypoint |
.cmd(commands) |
Set default command |
.add_local_file(local, remote) |
Copy a local file into the image |
.add_local_dir(local, remote) |
Copy a local directory into the image |
.dockerfile_commands(commands) |
Add raw Dockerfile instructions |
Example: Python data science environment:
from daytona import Daytona, CreateSandboxFromImageParams, Image
image = (
Image.debian_slim("3.12")
.pip_install("numpy", "pandas", "matplotlib", "scikit-learn")
.env({"PYTHONDONTWRITEBYTECODE": "1"})
.workdir("/home/daytona/project")
)
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromImageParams(image=image),
on_snapshot_create_logs=print, # stream build logs
)
Example: Node.js + TypeScript environment:
from daytona import Daytona, CreateSandboxFromImageParams, Image
image = Image.base("ubuntu:22.04").run_commands(
"apt-get update",
"apt-get install -y --no-install-recommends curl ca-certificates",
"curl -fsSL https://deb.nodesource.com/setup_20.x | bash -",
"apt-get install -y nodejs",
"npm install -g ts-node typescript",
)
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromImageParams(image=image, language="typescript"),
timeout=200,
on_snapshot_create_logs=print,
)
TypeScript equivalent:
import { Daytona, Image } from '@daytona/sdk'
const daytona = new Daytona()
const sandbox = await daytona.create(
{
image: Image.base('ubuntu:22.04').runCommands(
'apt-get update',
'apt-get install -y --no-install-recommends python3 python3-pip',
),
language: 'python',
},
{ timeout: 200, onSnapshotCreateLogs: console.log },
)
4.6 Sandbox Parameters Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
string | auto-generated | Human-readable sandbox name |
language |
enum | "python" |
python, typescript, or javascript |
os_user |
string | "daytona" |
OS user inside the sandbox |
env_vars |
dict | {} |
Environment variables |
labels |
dict | {} |
Custom metadata labels |
public |
bool | false |
Whether sandbox is publicly accessible |
auto_stop_interval |
int | 15 |
Minutes of inactivity before auto-stop (0 = never) |
auto_archive_interval |
int | 10080 (7d) |
Minutes stopped before auto-archive (0 = max interval) |
auto_delete_interval |
int | disabled | Minutes stopped before auto-delete (negative = disabled, 0 = immediate) |
volumes |
list | [] |
Volume mounts to attach |
network_block_all |
bool | false |
Block all outbound network access |
network_allow_list |
string | "" |
Comma-separated CIDR allowlist |
ephemeral |
bool | false |
If true, sets auto_delete_interval=0 |
image |
string/Image | default | Docker image or Image builder (from-image only) |
resources |
Resources | default | CPU/memory/disk (from-image only) |
snapshot |
string | none | Snapshot name (from-snapshot only) |
Warning
Setting
ephemeral=Truewill automatically delete the sandbox when it stops. If you also setauto_delete_interval, it will be ignored and overridden to 0. The SDK emits a warning in this case.
4.7 Sandbox Classes
Sandboxes come in three resource classes:
| Class | Resources |
|---|---|
| small | Limited CPU, memory, and disk |
| medium | Moderate resources |
| large | Maximum resources |
Resource availability and exact specifications depend on your organization's plan and the target region.
4.8 Labels
Labels are key-value pairs for organizing and filtering sandboxes:
# Set labels at creation
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
labels={"project": "data-pipeline", "env": "staging"}
)
)
# Update labels on a running sandbox
sandbox.set_labels({"project": "data-pipeline", "env": "production"})
await sandbox.setLabels({ public: 'true', environment: 'production' })
5. Common Tasks
5.1 Execute Shell Commands
response = sandbox.process.exec("ls -la /home/daytona")
print(response.result)
print(f"Exit code: {response.exit_code}")
const response = await sandbox.process.executeCommand('ls -la /home/daytona')
console.log(response.result)
console.log(`Exit code: ${response.exitCode}`)
5.2 Run Code with the Code Interpreter
The code interpreter executes Python code over WebSocket with streaming support:
result = sandbox.code_interpreter.run_code("""
import math
for i in range(5):
print(f"sqrt({i}) = {math.sqrt(i):.4f}")
""")
print(result.stdout)
if result.error:
print(f"Error: {result.error.name}: {result.error.value}")
With streaming callbacks (TypeScript):
const result = await sandbox.codeInterpreter.runCode(
`
import time
for i in range(5):
print(f"Step {i}")
time.sleep(0.5)
`,
{
onStdout: (msg) => process.stdout.write(`STDOUT: ${msg.output}`),
onStderr: (msg) => process.stderr.write(`STDERR: ${msg.output}`),
onError: (err) => console.error(`ERROR: ${err.name}: ${err.value}`),
timeout: 30,
},
)
5.3 Stateful Code Interpreter Contexts
Variables persist across run_code calls within the same context. Create isolated contexts when you need separate state:
# Default context - state persists
sandbox.code_interpreter.run_code("counter = 1")
result = sandbox.code_interpreter.run_code("counter += 1; print(counter)")
print(result.stdout) # Output: 2
# Isolated context
ctx = sandbox.code_interpreter.create_context()
sandbox.code_interpreter.run_code("x = 42", context=ctx)
result = sandbox.code_interpreter.run_code("print(x)", context=ctx)
print(result.stdout) # Output: 42
# Clean up
sandbox.code_interpreter.delete_context(ctx)
const ctx = await sandbox.codeInterpreter.createContext()
await sandbox.codeInterpreter.runCode('x = 10', { context: ctx })
const result = await sandbox.codeInterpreter.runCode('print(x)', { context: ctx })
console.log(result.stdout) // Output: 10
await sandbox.codeInterpreter.deleteContext(ctx)
5.4 Run Code with Language Runtime (codeRun)
For non-Python languages, use process.code_run which executes via the sandbox runtime:
// TypeScript code execution
const result = await sandbox.process.codeRun('console.log("Hello World from code!")')
console.log(result.result)
// Python code execution via process
const pyResult = await sandbox.process.codeRun('print("Hello from Python")')
console.log(pyResult.result)
The code_run method also returns chart artifacts when matplotlib plots are generated:
response = sandbox.process.code_run("""
import matplotlib.pyplot as plt
plt.plot([1, 2, 3], [1, 4, 9])
plt.title("Quadratic")
plt.show()
""")
if response.artifacts and response.artifacts.charts:
for chart in response.artifacts.charts:
print(f"Chart type: {chart.type}, title: {chart.title}")
if chart.png:
import base64
img_bytes = base64.b64decode(chart.png)
with open("chart.png", "wb") as f:
f.write(img_bytes)
5.5 File System Operations
Upload files:
from daytona import FileUpload
# Upload from bytes
sandbox.fs.upload_file(b"Hello, world!", "/home/daytona/hello.txt")
# Upload multiple files (from bytes and local paths)
sandbox.fs.upload_files([
FileUpload(source=b"content here", destination="project/config.json"),
FileUpload(source="/local/path/to/file.txt", destination="project/data.txt"),
])
Download files:
from daytona import FileDownloadRequest
# Download to memory
content = sandbox.fs.download_file("project/config.json")
print(content.decode("utf-8"))
# Download multiple files (some to disk, some to memory)
results = sandbox.fs.download_files([
FileDownloadRequest(source="project/config.json", destination="local-config.json"),
FileDownloadRequest(source="project/data.txt"), # to memory
])
for result in results:
if result.error:
print(f"Error: {result.error}")
elif isinstance(result.result, str):
print(f"Saved to {result.result}")
elif result.result:
print(f"Got {len(result.result)} bytes in memory")
List, search, and manipulate files:
# List files
files = sandbox.fs.list_files("/home/daytona")
# Create a directory
sandbox.fs.create_folder("project-files", "755")
# Search for files by pattern
matches = sandbox.fs.search_files("project-files", "*.json")
# Find files containing specific text
matches = sandbox.fs.find_files("project-files", "var obj1 = new Base();")
# Replace text across files
sandbox.fs.replace_in_files(
["project/config.json"],
'"debug": true',
'"debug": false',
)
TypeScript equivalents:
// Upload
await sandbox.fs.uploadFile(Buffer.from('Hello, World!'), '/home/daytona/hello.txt')
// Download
const content = await sandbox.fs.downloadFile('/home/daytona/hello.txt')
console.log(content.toString())
// Create folder
await sandbox.fs.createFolder('/home/daytona/new-dir', '755')
// List files
const files = await sandbox.fs.listFiles('/home/daytona')
5.6 Git Operations
# Clone a repository
sandbox.git.clone(
"https://github.com/example/repo",
"my-project",
"main", # branch
)
# Pull latest changes
sandbox.git.pull("my-project")
5.7 Exec Sessions (Persistent Shell State)
Exec sessions maintain shell state (environment variables, working directory) across multiple commands:
// Create a session
await sandbox.process.createSession('my-session')
// Execute commands in the session
const cmd1 = await sandbox.process.executeSessionCommand('my-session', {
command: 'export FOO=BAR',
})
// Environment persists across commands
const cmd2 = await sandbox.process.executeSessionCommand('my-session', {
command: 'echo $FOO',
})
console.log(cmd2.stdout) // Output: BAR
// Async execution with log streaming
const asyncCmd = await sandbox.process.executeSessionCommand('my-session', {
command: 'for i in 1 2 3; do echo $i; sleep 1; done',
runAsync: true,
})
// Stream logs
await sandbox.process.getSessionCommandLogs(
'my-session',
asyncCmd.cmdId,
(stdout) => console.log('[STDOUT]:', stdout),
(stderr) => console.log('[STDERR]:', stderr),
)
// Send input to a running command
await sandbox.process.sendSessionCommandInput('my-session', asyncCmd.cmdId, 'some input')
// Clean up
await sandbox.process.deleteSession('my-session')
5.8 PTY Sessions (Interactive Terminals)
PTY sessions provide full terminal emulation with resize support:
from daytona import PtySize
# Create a PTY session
pty = sandbox.process.create_pty_session(
id="my-terminal",
pty_size=PtySize(cols=120, rows=30),
)
# Send commands
pty.send_input("echo 'Hello from PTY'\n")
# Resize the terminal
pty.resize(PtySize(cols=80, rows=25))
# Read output using iterator
for data in pty:
text = data.decode("utf-8", errors="replace")
print(text, end="")
# Or use wait() with a callback and timeout
import threading
thread = threading.Thread(target=pty.wait, args=(handle_data, 10))
thread.start()
# Send exit to close
pty.send_input("exit\n")
# Or kill forcibly
pty.kill()
print(f"Exit code: {pty.exit_code}")
5.9 Computer Use (GUI Automation)
Computer use provides VNC-based mouse, keyboard, and screen control for GUI automation:
Mouse operations:
# Get current position
pos = sandbox.computer_use.mouse.get_position()
print(f"Mouse at: {pos.x}, {pos.y}")
# Move to coordinates
sandbox.computer_use.mouse.move(100, 200)
# Click (button: "left", "right", "middle"; count for double-click)
sandbox.computer_use.mouse.click(100, 200, button="left")
# Drag from one point to another
sandbox.computer_use.mouse.drag(100, 200, 300, 400)
# Scroll
sandbox.computer_use.mouse.scroll(0, -3) # scroll up
Keyboard operations:
# Type text
sandbox.computer_use.keyboard.type("Hello, World!")
# Press a key
sandbox.computer_use.keyboard.press("enter")
# Hotkey combinations
sandbox.computer_use.keyboard.hotkey("ctrl", "c")
Screenshots:
from daytona import ScreenshotOptions, ScreenshotRegion
# Full screen screenshot
screenshot = sandbox.computer_use.screen.take_screenshot()
# Screenshot with options
screenshot = sandbox.computer_use.screen.take_screenshot(
options=ScreenshotOptions(
show_cursor=True,
fmt="png",
quality=80,
scale=0.5,
)
)
# Screenshot of a region
screenshot = sandbox.computer_use.screen.take_screenshot(
region=ScreenshotRegion(x=0, y=0, width=800, height=600)
)
Caution
Known issue (#4417): Named keys like
Escapemay produceshift+escapedue to upstream robotgo behavior. If you encounter unexpected key behavior, use the key's lowercase name or test with simple keys first.
5.10 Language Server Protocol (LSP)
Start a language server for code intelligence:
from daytona import LspCompletionPosition
# Start an LSP server
lsp = sandbox.create_lsp_server("typescript", "my-project")
lsp.start()
# Open a document
lsp.did_open("my-project/src/index.ts")
# Get document symbols
symbols = lsp.document_symbols("my-project/src/index.ts")
print("Symbols:", symbols)
# Get completions at a position
completions = lsp.completions(
"my-project/src/index.ts",
LspCompletionPosition(line=12, character=18),
)
print("Completions:", completions)
# Notify of document close
lsp.did_close("my-project/src/index.ts")
5.11 Chart Generation and Extraction
When executing matplotlib code via process.code_run, Daytona automatically extracts chart data:
from daytona import (
Daytona, CreateSandboxFromImageParams, Image,
Chart, ChartType, LineChart, BarChart, PieChart,
ScatterChart, BoxAndWhiskerChart, CompositeChart,
)
daytona = Daytona()
sandbox = daytona.create(
CreateSandboxFromImageParams(
image=Image.debian_slim("3.13").pip_install("matplotlib"),
),
on_snapshot_create_logs=print,
)
code = """
import matplotlib.pyplot as plt
plt.bar(['A', 'B', 'C'], [10, 20, 15])
plt.title('Sales by Region')
plt.xlabel('Region')
plt.ylabel('Revenue ($M)')
plt.show()
"""
response = sandbox.process.code_run(code)
if response.artifacts and response.artifacts.charts:
for chart in response.artifacts.charts:
print(f"Type: {chart.type}, Title: {chart.title}")
if isinstance(chart, BarChart):
for elem in chart.elements:
print(f" {elem.label}: {elem.value}")
daytona.delete(sandbox)
Supported chart types:
| Type | Class | Data Elements |
|---|---|---|
line |
LineChart |
PointData (label, points) |
scatter |
ScatterChart |
PointData (label, points) |
bar |
BarChart |
BarData (label, value, group) |
pie |
PieChart |
PieData (label, angle, radius) |
box_and_whisker |
BoxAndWhiskerChart |
BoxAndWhiskerData (label, min, Q1, median, Q3, max, outliers) |
composite_chart |
CompositeChart |
Nested sub-charts |
5.12 Network Controls
Control outbound network access per sandbox:
from daytona import CreateSandboxFromSnapshotParams
# Default: all network access allowed
sandbox = daytona.create()
# Block all outbound network access
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(network_block_all=True)
)
# Allow only specific CIDR ranges
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
network_allow_list="192.168.1.0/16,10.0.0.0/24"
)
)
5.13 Volumes (Persistent Storage)
Volumes persist data across sandbox lifecycles. Multiple sandboxes can mount the same volume:
import { Daytona } from '@daytona/sdk'
const daytona = new Daytona()
// Create or get a volume (true = create if not exists)
const volume = await daytona.volume.get('my-volume', true)
// Mount to a sandbox
const sandbox1 = await daytona.create({
language: 'typescript',
volumes: [{ volumeId: volume.id, mountPath: '/home/daytona/data' }],
})
// Write data
await sandbox1.fs.uploadFile(Buffer.from('shared data'), '/home/daytona/data/shared.txt')
// Mount same volume to another sandbox
const sandbox2 = await daytona.create({
language: 'typescript',
volumes: [{ volumeId: volume.id, mountPath: '/home/daytona/files' }],
})
// Read the data written by sandbox1
const files = await sandbox2.fs.listFiles('/home/daytona/files')
console.log('Shared files:', files)
Subpath mounting isolates specific directories within a volume:
const sandbox = await daytona.create({
volumes: [{ volumeId: volume.id, mountPath: '/data', subpath: 'users/alice' }],
})
// Only sees files within volume-root/users/alice/
CLI volume commands:
daytona volume list
daytona volume list -f json
5.14 Snapshots
Snapshots capture the full state of a sandbox for fast reproduction:
# List snapshots
page, limit = 1, 10
snapshots = daytona.snapshot.list(page=page, limit=limit)
for snap in snapshots.items:
print(f"{snap.name} (state: {snap.state})")
# Create a sandbox from a snapshot
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(snapshot="my-snapshot")
)
Go snapshot example:
ctx := context.Background()
page := 1
limit := 5
snapshots, err := client.Snapshot.List(ctx, &page, &limit)
if err != nil {
log.Fatalf("Failed to list snapshots: %v", err)
}
log.Printf("Total snapshots: %d\n", snapshots.Total)
CLI snapshot commands:
daytona snapshot list
daytona snapshot list -f json
5.15 Organizations
Organizations group users, sandboxes, and resources. Switch between organizations in the CLI:
daytona organization list
daytona organization use
5.16 Auto-Stop, Auto-Archive, and Auto-Delete
Control sandbox lifecycle automation:
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
auto_stop_interval=30, # stop after 30 min idle
auto_archive_interval=1440, # archive after 1 day stopped
auto_delete_interval=4320, # delete after 3 days stopped
)
)
Ephemeral sandboxes delete immediately upon stopping:
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(ephemeral=True)
)
# Sandbox is automatically deleted when it stops
5.17 Preview URLs
Get a public preview URL for a sandbox port:
daytona preview-url <sandbox-id>
5.18 SSH into a Sandbox
daytona ssh <sandbox-id>
5.19 Execute Commands via CLI
daytona exec <sandbox-id> -- echo "Hello from CLI"
5.20 Using the MCP Server
Daytona includes a Model Context Protocol (MCP) server for AI agent integration. The MCP server exposes sandbox tools (create, destroy, file operations, command execution, Git, preview URLs) via the MCP standard.
daytona mcp
The MCP server provides these tools:
| Tool | Description |
|---|---|
CreateSandbox |
Create a new sandbox |
DestroySandbox |
Delete a sandbox |
FileUpload |
Upload a file to a sandbox |
FileDownload |
Download a file from a sandbox |
FileInfo |
Get file metadata |
ListFiles |
List files in a directory |
MoveFile |
Move or rename a file |
DeleteFile |
Delete a file |
CreateFolder |
Create a directory |
ExecuteCommand |
Run a shell command |
PreviewLink |
Get a preview URL |
GitClone |
Clone a Git repository |
5.21 Output Formatting
The CLI supports multiple output formats:
# Default table format
daytona list
# JSON output
daytona list -f json
# YAML output
daytona list -f yaml
The -f flag works with list, info, and other read commands.
5.22 Region Selection
Target a specific region when creating sandboxes:
config = DaytonaConfig(
api_key="your-key",
target="us", # or "eu", etc.
)
daytona = Daytona(config)
Or via environment variable:
export DAYTONA_TARGET=eu
5.23 Pagination
List operations support pagination:
# Python
result = daytona.list() # uses defaults
print(f"Page items: {len(result.items)}, Total: {result.total}")
// Go
page := 1
limit := 10
result, err := client.List(ctx, &page, &limit)
5.24 Async Python SDK
The Python SDK provides async variants for all operations:
import asyncio
from daytona import Daytona
async def main():
daytona = Daytona()
sandbox = await daytona.create_async()
result = await sandbox.code_interpreter.run_code_async(
"print('async hello')"
)
print(result.stdout)
await daytona.delete_async(sandbox)
asyncio.run(main())
5.25 Streaming Build Logs
Monitor sandbox image builds in real time:
sandbox = daytona.create(
CreateSandboxFromImageParams(
image=Image.debian_slim("3.12").pip_install("tensorflow"),
),
on_snapshot_create_logs=print,
)
const sandbox = await daytona.create(
{ image: Image.debianSlim('3.12').pipInstall('tensorflow') },
{ onSnapshotCreateLogs: console.log },
)
5.26 Environment Variables in Sandboxes
Set environment variables at creation or pass them to code execution:
# At creation
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(
env_vars={"DATABASE_URL": "postgres://...", "API_KEY": "secret"}
)
)
# At code execution time
result = sandbox.code_interpreter.run_code(
"import os; print(os.environ['MY_VAR'])",
envs={"MY_VAR": "runtime-value"},
)
6. Troubleshooting
6.1 Authentication Failures
Error: DaytonaAuthenticationError (HTTP 401)
Cause: Invalid, expired, or missing API key or JWT token.
Solution:
- Verify your API key is correct:
echo $DAYTONA_API_KEY - If using the CLI, re-authenticate:
daytona login - If using JWT, ensure
organization_idis also set - Check that the API URL matches your environment
Prevention: Store API keys in environment variables rather than hardcoding them. Use the CLI's profile system for persistent authentication.
6.2 Authorization Denied
Error: DaytonaAuthorizationError (HTTP 403)
Cause: Your account lacks permission for the requested operation, or the organization is suspended.
Solution: Verify your role within the organization. Contact your organization admin for elevated permissions.
Prevention: Use the organization management commands to verify your access level before performing admin operations.
6.3 Sandbox Not Found
Error: DaytonaNotFoundError (HTTP 404)
Cause: The sandbox ID is invalid, or the sandbox was already deleted/archived.
Solution:
- List active sandboxes:
daytona list - Check if the sandbox was auto-deleted or auto-archived
- Verify the sandbox ID is correct
Prevention: Use auto_delete_interval=-1 (disabled) for sandboxes you need to persist.
6.4 Sandbox Creation Timeout
Error: DaytonaTimeoutError during daytona.create()
Cause: Image build is taking longer than the timeout, or the region is experiencing high demand.
Solution:
- Increase the timeout:
daytona.create(params, timeout=300) - Use snapshots instead of building from image for faster starts
- Pre-build complex images and create snapshots from them
Prevention: Use Image.debian_slim() or snapshots for fastest creation. Reserve custom Image.base() builds for when you need specific system packages.
6.5 Code Interpreter Timeout
Error: DaytonaTimeoutError during code_interpreter.run_code()
Cause: Code execution exceeded the configured timeout.
Solution:
- Increase the timeout:
sandbox.code_interpreter.run_code(code, timeout=60) - Break long-running code into smaller chunks
- Use
process.exec()for long-running shell operations instead
Prevention: Set appropriate timeouts based on expected execution time. The code interpreter is designed for interactive code snippets, not long-running batch jobs.
6.6 WebSocket Connection Failed
Error: DaytonaConnectionError: Failed to execute code: ...
Cause: Network connectivity issues between client and sandbox, or sandbox is not in started state.
Solution:
- Verify sandbox state:
sandbox.stateshould be"started" - Start the sandbox if stopped:
sandbox.start() - Check your network connection and firewall rules
Prevention: Always check sandbox state before executing code operations.
6.7 Empty Code Execution
Error: DaytonaValidationError: Code is required for execution
Cause: Passing an empty string or whitespace-only string to run_code().
Solution: Ensure the code string is non-empty and contains actual code.
6.8 Git Clone Fails on Small Sandboxes
Issue: #4544 - The toolbox git clone uses pure-Go go-git, which can fail on sandboxes with limited memory.
Cause: The go-git library loads objects into memory, which can exceed the memory limits of small sandbox classes.
Solution:
- Use a larger sandbox class
- Clone via
sandbox.process.exec("git clone ...")which uses the systemgitbinary instead - Clone only the needed branch with
--single-branch --depth 1
Prevention: For large repositories, prefer the system Git binary via exec over the SDK's built-in Git operations.
6.9 Docker-in-Docker Connection Failures
Issue: #4461 - Sandboxes using Docker-in-Docker base images may fail to connect.
Cause: The Docker daemon inside the sandbox may not start properly depending on the base image configuration.
Solution: Use the official Daytona-supported sandbox images with Docker support. Check sandbox logs for Docker daemon startup errors.
6.10 Toolbox API Proxy 502 Errors
Issue: #4545 - The toolbox API proxy returns bare 502 with empty body on upstream timeout.
Cause: Internal request to the sandbox daemon times out, and the proxy does not forward a useful error message.
Solution:
- Retry the operation
- Check if the sandbox is under heavy load
- Increase operation timeouts on the client side
6.11 File Listing Path Mismatch
Issue: #4542 - listFiles client calls GET /files but the daemon responds to GET /files/.
Cause: Trailing slash mismatch between the client SDK and the daemon API.
Solution: Ensure paths used in file operations include or exclude trailing slashes consistently. This is being tracked upstream.
6.12 TypeScript SDK getEnvVar on Cloudflare Workers
Issue: #4484 - getEnvVar() does not read process.env on Cloudflare Workers.
Cause: Cloudflare Workers do not provide a process.env object in the same way Node.js does.
Solution: Pass configuration explicitly rather than relying on environment variable auto-detection:
const daytona = new Daytona({
apiKey: env.DAYTONA_API_KEY, // Cloudflare Worker env binding
apiUrl: env.DAYTONA_API_URL,
})
Prevention: Always pass explicit configuration when running in serverless environments.
6.13 Java SDK WebSocket Callbacks Not Fired
Issue: #4558 - getSessionCommandLogs WebSocket callbacks are not triggered for plain-text log frames.
Cause: The Java SDK WebSocket handler only processes frames matching the expected demux format, missing plain-text frames.
Solution: Use polling-based log retrieval as a workaround until the issue is resolved upstream.
6.14 Computer Use Keyboard Named Keys
Issue: #4417 - Named keys like Escape produce shift+escape.
Cause: Upstream robotgo library behavior applies shift modifier unexpectedly.
Solution: Use lowercase key names and test keyboard interactions carefully. For common shortcuts, use hotkey() which handles modifier keys explicitly.
6.15 Rate Limiting
Error: DaytonaRateLimitError (HTTP 429)
Cause: Too many API requests in a short time window.
Solution:
- Implement exponential backoff retry logic
- Batch operations where possible (e.g.,
upload_filesinstead of multipleupload_filecalls) - Use
connection_pool_maxsizeto control concurrency
6.16 Resource Conflict
Error: DaytonaConflictError (HTTP 409)
Cause: Attempting to create a resource with a name that already exists.
Solution: Use a unique name, or retrieve the existing resource with daytona.get().
6.17 Organization Suspended
Error: Organization is suspended: <reason>
Cause: Your organization has been suspended, possibly due to billing issues.
Solution: Contact Daytona support or check your billing status in the dashboard.
6.18 No Profiles Found (CLI)
Error: no profiles found. Run 'daytona login' to authenticate
Cause: CLI config file has no profiles, or was reset.
Solution: Run daytona login to create a new profile through browser-based authentication.
6.19 No Active Organization (CLI)
Error: no active organization found. Run 'daytona organization use' to select an organization
Cause: Multiple organizations are available but none is selected.
Solution: Run daytona organization use and select an organization.
6.20 Sandbox Auto-Stopped Unexpectedly
Cause: The auto_stop_interval (default 15 minutes) triggered because no sandbox events occurred.
Solution:
- Set a longer
auto_stop_interval - Set
auto_stop_interval=0to disable auto-stop - Keep the sandbox active by running periodic operations
6.21 Sandbox Archived Unexpectedly
Cause: The auto_archive_interval (default 7 days) triggered after the sandbox remained stopped.
Solution:
- Start the sandbox to unarchive it
- Set a longer
auto_archive_intervalat creation time
6.22 Image Build Failures
Error: Sandbox state becomes build_failed
Cause: The Dockerfile generated by the Image builder or a custom Dockerfile has errors.
Solution:
- Test the Dockerfile locally:
print(image.dockerfile())to inspect it - Stream build logs:
on_snapshot_create_logs=print - Check that all package names are correct and repositories are accessible
6.23 Connection Pool Exhausted
Error: Requests hanging or timing out under high concurrency.
Cause: The default connection pool of 250 is exhausted.
Solution: Set connection_pool_maxsize=None in DaytonaConfig for unlimited connections.
6.24 PTY Session Exit Code
Issue: PTY session shows unexpected exit code.
Cause: The command inside the PTY exited with an error, or the session was killed.
Solution: Check pty_handle.exit_code and pty_handle.error after the session ends for diagnostics.
6.25 Deprecated server_url Warning
Warning: 'server_url' is deprecated and will be removed in a future version. Use 'api_url' instead.
Cause: Your code uses the deprecated server_url field in DaytonaConfig.
Solution: Replace server_url with api_url:
# Before
config = DaytonaConfig(server_url="https://app.daytona.io/api")
# After
config = DaytonaConfig(api_url="https://app.daytona.io/api")
6.26 Invalid Python Version in Image Builder
Error: DaytonaValidationError: Unsupported Python version
Cause: The Python version passed to Image.debian_slim() is not in the supported list.
Solution: Use one of the supported series: 3.9, 3.10, 3.11, 3.12, 3.13.
6.27 File Not Found in Image Builder
Error: DaytonaNotFoundError: Local file ... does not exist
Cause: A path passed to add_local_file(), add_local_dir(), pip_install_from_requirements(), or from_dockerfile() does not exist on the local machine.
Solution: Verify the file path exists and is accessible. Use absolute paths to avoid working-directory ambiguity.
Tip
When debugging issues, always check
sandbox.statefirst. Many errors stem from operating on a sandbox that is stopped, archived, or in a transient state. Usesandbox.start()to restore a stopped sandbox before performing operations.
7. FAQ
How do I get an API key?
Sign up at app.daytona.io, navigate to your account settings, and generate an API key. Set it as the DAYTONA_API_KEY environment variable.
What programming languages does the code interpreter support?
The code interpreter (WebSocket-based run_code / runCode) executes Python only. For other languages, use process.code_run (which runs code through the sandbox's language runtime) or process.exec / process.executeCommand to run arbitrary shell commands.
What is the difference between code_interpreter.run_code and process.code_run?
code_interpreter.run_code uses a WebSocket-based Python interpreter with stateful contexts and real-time streaming callbacks. process.code_run executes code via the sandbox runtime and can handle multiple languages, but does not support persistent state between calls. process.code_run also returns chart artifacts from matplotlib plots.
What is the difference between process.exec and exec sessions?
process.exec (Python) / process.executeCommand (TypeScript) runs a single command in a fresh shell. Exec sessions (createSession, executeSessionCommand) maintain shell state (environment variables, working directory) across multiple commands.
How fast do sandboxes start? From a snapshot: typically a few seconds. From a custom image (first build): depends on image complexity and package installation. Subsequent builds are cached.
Can I use Docker inside a sandbox? Docker-in-Docker is possible but has known connectivity issues (#4461). Use official Daytona-supported Docker images for the best experience.
How do volumes work?
Volumes are persistent storage that survives sandbox deletion. Create a volume with daytona.volume.get('name', true), then mount it to sandboxes via the volumes parameter. Multiple sandboxes can mount the same volume simultaneously.
What happens when a sandbox is archived?
An archived sandbox's compute resources are released but its filesystem state is preserved. Starting an archived sandbox restores it. Archives happen automatically based on auto_archive_interval (default 7 days after stopping).
What is an ephemeral sandbox?
A sandbox created with ephemeral=True is automatically deleted as soon as it stops. This is equivalent to setting auto_delete_interval=0. Useful for one-off tasks and CI/CD.
How do I control network access?
Use network_block_all=True to block all outbound traffic, or network_allow_list="10.0.0.0/8,172.16.0.0/12" to allow specific CIDR ranges. Default is full network access.
What are sandbox labels?
Labels are key-value pairs attached to sandboxes for metadata and filtering. Set them at creation or update them later with sandbox.set_labels().
What regions are available?
Regions depend on your organization's configuration. Use the target parameter in DaytonaConfig or the DAYTONA_TARGET environment variable to select a region.
What is the MCP server?
The MCP (Model Context Protocol) server lets AI agents interact with Daytona sandboxes. Run daytona mcp to start it. It exposes tools for sandbox creation, file operations, command execution, and Git operations.
Can I use Daytona with Cloudflare Workers?
Yes, but pass configuration explicitly instead of relying on process.env auto-detection, which does not work in the Cloudflare Workers runtime (#4484).
What chart types does the code interpreter extract?
Line, scatter, bar, pie, box-and-whisker, and composite charts. Charts are extracted from matplotlib plt.show() calls via process.code_run.
How do I resize a PTY session?
Call pty_handle.resize(PtySize(cols=80, rows=25)) at any time during an active PTY session.
How do I send input to an async exec session command?
Use sandbox.process.sendSessionCommandInput(sessionId, commandId, 'your input') to send stdin to a running async command.
What is the default API URL?
https://app.daytona.io/api. Override it with api_url in DaytonaConfig or the DAYTONA_API_URL environment variable.
What is the connection_pool_maxsize setting?
It limits the number of simultaneous HTTP connections the SDK maintains. Default is 250. Set to None for unlimited connections, which is recommended when running many concurrent long-lived operations.
How do I open the Daytona documentation?
Run daytona docs to open the official documentation at daytona.io/docs in your default browser.
What are the CLI command aliases?
The CLI supports shorthand aliases: create=add/new, delete=remove/rm, list=ls, info=view/inspect, update=set, logs=log, forward=fwd, code=open, install=i, uninstall=u.
Where is the CLI config stored?
In $DAYTONA_CONFIG_DIR/config.json, or $XDG_CONFIG_HOME/daytona/config.json (Linux/macOS), or %APPDATA%/daytona/config.json (Windows).
How do I switch between CLI profiles?
The config file supports multiple profiles. Set the active profile by updating activeProfile in the config, or set both DAYTONA_API_URL and DAYTONA_API_KEY environment variables to bypass profiles entirely.
What is the Image.debian_slim() base?
It creates a Debian Bookworm slim image with the specified Python version, pre-installs gcc, gfortran, and build-essential, upgrades pip, and sets the frontend to non-interactive. Supported Python series: 3.9, 3.10, 3.11, 3.12, 3.13.
Can I build an image from my own Dockerfile?
Yes. Use Image.from_dockerfile("path/to/Dockerfile"). The builder automatically extracts COPY sources from the Dockerfile and uploads them as build context.
What happens if I set both ephemeral and auto_delete_interval?
The SDK emits a warning and ephemeral wins: auto_delete_interval is forced to 0 (delete immediately on stop).
How do I use subpath mounting with volumes?
Pass a subpath parameter in the volume mount: { volumeId: vol.id, mountPath: '/data', subpath: 'users/alice' }. The sandbox only sees files under that subpath.
What error types does the SDK provide?
The error hierarchy is: DaytonaError (base), DaytonaNotFoundError (404), DaytonaAuthenticationError (401), DaytonaAuthorizationError (403), DaytonaConflictError (409), DaytonaRateLimitError (429), DaytonaValidationError (400), DaytonaConnectionError, and DaytonaTimeoutError. All errors include message, status_code, error_code, and headers attributes.
What LSP languages are supported?
Python, TypeScript, and JavaScript (LspLanguageId.PYTHON, LspLanguageId.TYPESCRIPT, LspLanguageId.JAVASCRIPT). The appropriate language server must be installed in the sandbox image.