Skip to content

Declarative Builder

Daytona’s declarative builder provides a powerful, code-first approach to defining dependencies for Sandboxes. Instead of importing images from a container registry, you can programmatically define them using the SDK.

Overview

The declarative builder system supports two primary workflows:

  1. Declarative Images: Build images with varying dependencies on demand when creating Sandboxes
  2. Pre-built Snapshots: Create and register ready-to-use Snapshots that can be shared across multiple Sandboxes

Declarative Image Building

You can create declarative images on-the-fly when creating Sandboxes. This is ideal for iterating quickly without creating separate Snapshots.

Declarative images are cached for 24 hours, and will be automatically reused when running the same script. Thus, subsequent runs on the same Runner will be almost instantaneous.

# Define a simple declarative image with Python packages
declarative_image = (
Image.debian_slim("3.12")
.pip_install(["requests", "pytest"])
.workdir("/home/daytona")
)
# Create a new Sandbox with the declarative image and stream the build logs
sandbox = daytona.create(
CreateSandboxFromImageParams(image=declarative_image),
timeout=0,
on_snapshot_create_logs=print,
)

See: CreateSandboxFromImageParams (Python SDK), CreateSandboxFromImageParams (TypeScript SDK)

Creating Pre-built Snapshots

For images that will be reused across multiple Sandboxes, create a pre-built Snapshot. This Snapshot will remain visible in the Daytona dashboard and be permanently cached, ensuring instant availability without rebuilding.

# Create a simple Python data science image
snapshot_name = "data-science-snapshot"
image = (
Image.debian_slim("3.12")
.pip_install(["pandas", "numpy"])
.workdir("/home/daytona")
)
# Create the Snapshot and stream the build logs
daytona.snapshot.create(
CreateSnapshotParams(
name=snapshot_name,
image=image,
),
on_logs=print,
)
# Create a new Sandbox using the pre-built Snapshot
sandbox = daytona.create(
CreateSandboxFromSnapshotParams(snapshot=snapshot_name)
)

See: CreateSnapshotParams (Python SDK), CreateSnapshotParams (TypeScript SDK)

Image Configuration

The Daytona SDK provides methods to define images programmatically using the Daytona SDK. You can specify base images, install packages, add files, set environment variables, and more.

For a complete API reference and method signatures, check the Python and TypeScript SDK references.

Base Image Selection

These examples demonstrate how to select and configure base images:

# Create an image from a base
image = Image.base("python:3.12-slim-bookworm")
# Use a Debian slim image with Python 3.12
image = Image.debian_slim("3.12")

See: base (Python SDK), debian_slim (Python SDK), base (TypeScript SDK), debianSlim (TypeScript SDK)

Package Management

Use these methods to install Python packages and dependencies:

# Add pip packages
image = Image.debian_slim("3.12").pip_install("requests", "pandas")
# Install from requirements.txt
image = Image.debian_slim("3.12").pip_install_from_requirements("requirements.txt")
# Install from pyproject.toml (with optional dependencies)
image = Image.debian_slim("3.12").pip_install_from_pyproject("pyproject.toml", optional_dependencies=["dev"])

See: pip_install (Python SDK), pip_install_from_requirements (Python SDK), pip_install_from_pyproject (Python SDK), pipInstall (TypeScript SDK), pipInstallFromRequirements (TypeScript SDK), pipInstallFromPyproject (TypeScript SDK)

File System Operations

These examples show how to add files and directories to your image:

# Add a local file
image = Image.debian_slim("3.12").add_local_file("package.json", "/home/daytona/package.json")
# Add a local directory
image = Image.debian_slim("3.12").add_local_dir("src", "/home/daytona/src")

See: add_local_file (Python SDK), add_local_dir (Python SDK), addLocalFile (TypeScript SDK), addLocalDir (TypeScript SDK)

Environment Configuration

Configure environment variables and working directories with these methods:

# Set environment variables
image = Image.debian_slim("3.12").env({"PROJECT_ROOT": "/home/daytona"})
# Set working directory
image = Image.debian_slim("3.12").workdir("/home/daytona")

See: env (Python SDK), workdir (Python SDK), env (TypeScript SDK), workdir (TypeScript SDK)

Commands and Entrypoints

Execute commands during build and configure container startup behavior:

# Run shell commands during build
image = Image.debian_slim("3.12").run_commands(
'apt-get update && apt-get install -y git',
'groupadd -r daytona && useradd -r -g daytona -m daytona',
'mkdir -p /home/daytona/workspace'
)
# Set entrypoint
image = Image.debian_slim("3.12").entrypoint(["/bin/bash"])
# Set default command
image = Image.debian_slim("3.12").cmd(["/bin/bash"])

See: run_commands (Python SDK), entrypoint (Python SDK), cmd (Python SDK), runCommands (TypeScript SDK), entrypoint (TypeScript SDK), cmd (TypeScript SDK)

Dockerfile Integration

Integrate existing Dockerfiles or add custom Dockerfile commands:

# Add custom Dockerfile commands
image = Image.debian_slim("3.12").dockerfile_commands(["RUN echo 'Hello, world!'"])
# Use an existing Dockerfile
image = Image.from_dockerfile("Dockerfile")
# Extend an existing Dockerfile
image = Image.from_dockerfile("app/Dockerfile").pip_install(["numpy"])

See: dockerfile_commands (Python SDK), from_dockerfile (Python SDK), dockerfileCommands (TypeScript SDK), fromDockerfile (TypeScript SDK)

Best Practices

Use the following best practices when working with the declarative builder:

  1. Layer Optimization: Group related operations to minimize Docker layers
  2. Cache Utilization: Identical build commands and context will be cached and subsequent builds will be almost instant
  3. Security: Create non-root users for application workloads
  4. Resource Efficiency: Use slim base images when appropriate
  5. Context Minimization: Only include necessary files in the build context