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:
- Declarative Images: Build images with varying dependencies on demand when creating Sandboxes
- 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 packagesdeclarative_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 logssandbox = daytona.create( CreateSandboxFromImageParams(image=declarative_image), timeout=0, on_snapshot_create_logs=print,)
// Define a simple declarative image with Python packagesconst declarativeImage = Image.debianSlim('3.12') .pipInstall(['requests', 'pytest']) .workdir('/home/daytona')
// Create a new Sandbox with the declarative image and stream the build logsconst sandbox = await daytona.create( { image: declarativeImage, }, { timeout: 0, onSnapshotCreateLogs: console.log, })
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 imagesnapshot_name = "data-science-snapshot"
image = ( Image.debian_slim("3.12") .pip_install(["pandas", "numpy"]) .workdir("/home/daytona"))
# Create the Snapshot and stream the build logsdaytona.snapshot.create( CreateSnapshotParams( name=snapshot_name, image=image, ), on_logs=print,)
# Create a new Sandbox using the pre-built Snapshotsandbox = daytona.create( CreateSandboxFromSnapshotParams(snapshot=snapshot_name))
// Create a simple Python data science imageconst snapshotName = 'data-science-snapshot'
const image = Image.debianSlim('3.12') .pipInstall(['pandas', 'numpy']) .workdir('/home/daytona')
// Create the Snapshot and stream the build logsawait daytona.snapshot.create( { name: snapshotName, image, }, { onLogs: console.log, })
// Create a new Sandbox using the pre-built Snapshotconst sandbox = await daytona.create({ snapshot: snapshotName,})
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 baseimage = Image.base("python:3.12-slim-bookworm")
# Use a Debian slim image with Python 3.12image = Image.debian_slim("3.12")
// Create an image from a baseconst image = Image.base('python:3.12-slim-bookworm')
// Use a Debian slim image with Python 3.12const image = Image.debianSlim('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 packagesimage = Image.debian_slim("3.12").pip_install("requests", "pandas")
# Install from requirements.txtimage = 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"])
// Add pip packagesconst image = Image.debianSlim('3.12').pipInstall(['requests', 'pandas'])
// Install from requirements.txtconst image = Image.debianSlim('3.12').pipInstallFromRequirements('requirements.txt')
// Install from pyproject.toml (with optional dependencies)const image = Image.debianSlim('3.12').pipInstallFromPyproject('pyproject.toml', { optionalDependencies: ['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 fileimage = Image.debian_slim("3.12").add_local_file("package.json", "/home/daytona/package.json")
# Add a local directoryimage = Image.debian_slim("3.12").add_local_dir("src", "/home/daytona/src")
// Add a local fileconst image = Image.debianSlim('3.12').addLocalFile('package.json', '/home/daytona/package.json')
// Add a local directoryconst image = Image.debianSlim('3.12').addLocalDir('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 variablesimage = Image.debian_slim("3.12").env({"PROJECT_ROOT": "/home/daytona"})
# Set working directoryimage = Image.debian_slim("3.12").workdir("/home/daytona")
// Set environment variablesconst image = Image.debianSlim('3.12').env({ PROJECT_ROOT: '/home/daytona' })
// Set working directoryconst image = Image.debianSlim('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 buildimage = 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 entrypointimage = Image.debian_slim("3.12").entrypoint(["/bin/bash"])
# Set default commandimage = Image.debian_slim("3.12").cmd(["/bin/bash"])
// Run shell commands during buildconst image = Image.debianSlim('3.12').runCommands( 'apt-get update && apt-get install -y git', 'groupadd -r daytona && useradd -r -g daytona -m daytona', 'mkdir -p /home/daytona/workspace')
// Set entrypointconst image = Image.debianSlim('3.12').entrypoint(['/bin/bash'])
// Set default commandconst image = Image.debianSlim('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 commandsimage = Image.debian_slim("3.12").dockerfile_commands(["RUN echo 'Hello, world!'"])
# Use an existing Dockerfileimage = Image.from_dockerfile("Dockerfile")
# Extend an existing Dockerfileimage = Image.from_dockerfile("app/Dockerfile").pip_install(["numpy"])
// Add custom Dockerfile commandsconst image = Image.debianSlim('3.12').dockerfileCommands(['RUN echo "Hello, world!"'])
// Use an existing Dockerfileconst image = Image.fromDockerfile('Dockerfile')
// Extend an existing Dockerfileconst image = Image.fromDockerfile("app/Dockerfile").pipInstall(['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:
- Layer Optimization: Group related operations to minimize Docker layers
- Cache Utilization: Identical build commands and context will be cached and subsequent builds will be almost instant
- Security: Create non-root users for application workloads
- Resource Efficiency: Use slim base images when appropriate
- Context Minimization: Only include necessary files in the build context