Jesse A. Green / notebook

Daytona User Guide

Generated May 2026 from daytonaio/daytona at 4c6a681

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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_KEY environment variable. You can generate an API key from the Daytona dashboard. For the CLI, run daytona login to 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 (or zsh, 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-completion is 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_url configuration field is deprecated. Always use api_url instead. If both are provided, api_url takes precedence. server_url will 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 (if DAYTONA_CONFIG_DIR is 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=True will automatically delete the sandbox when it stops. If you also set auto_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 Escape may produce shift+escape due 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:

  1. Verify your API key is correct: echo $DAYTONA_API_KEY
  2. If using the CLI, re-authenticate: daytona login
  3. If using JWT, ensure organization_id is also set
  4. 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:

  1. List active sandboxes: daytona list
  2. Check if the sandbox was auto-deleted or auto-archived
  3. 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:

  1. Increase the timeout: daytona.create(params, timeout=300)
  2. Use snapshots instead of building from image for faster starts
  3. 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:

  1. Increase the timeout: sandbox.code_interpreter.run_code(code, timeout=60)
  2. Break long-running code into smaller chunks
  3. 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:

  1. Verify sandbox state: sandbox.state should be "started"
  2. Start the sandbox if stopped: sandbox.start()
  3. 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:

  1. Use a larger sandbox class
  2. Clone via sandbox.process.exec("git clone ...") which uses the system git binary instead
  3. 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:

  1. Retry the operation
  2. Check if the sandbox is under heavy load
  3. 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:

  1. Implement exponential backoff retry logic
  2. Batch operations where possible (e.g., upload_files instead of multiple upload_file calls)
  3. Use connection_pool_maxsize to 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:

  1. Set a longer auto_stop_interval
  2. Set auto_stop_interval=0 to disable auto-stop
  3. 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:

  1. Start the sandbox to unarchive it
  2. Set a longer auto_archive_interval at 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:

  1. Test the Dockerfile locally: print(image.dockerfile()) to inspect it
  2. Stream build logs: on_snapshot_create_logs=print
  3. 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.state first. Many errors stem from operating on a sandbox that is stopped, archived, or in a transient state. Use sandbox.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.