Images
Register, build, and capture the images that sandboxes boot from.
An image is the filesystem a sandbox boots from, together with the environment variables, working directory, entrypoint, and command the sandbox starts with. Daytona accepts standard OCI images, the same ones you build and push with Docker, and converts each one into a boot-optimized format when you register it. Images belong to a project, and a sandbox references its image by name or ID. A sandbox create does not pull from a registry, so a sandbox boots only from an image already registered in the project.
An image comes from one of four sources: a public or private registry, a Dockerfile build, the filesystem of a running sandbox, or a Windows base image that Daytona provides. Private registries authenticate with the registry credentials you store for their host. A new image is pending when its build is queued, building when it joins an identical build in progress, or ready when it reuses an identical finished build. Every image ends as ready or failed, and sandboxes boot only from a ready image. A named image stays until you delete it. An image without a name is anonymous, and Daytona deletes it once it goes unused for its idle window.
Every sandbox created from an image starts with the same filesystem and configuration. An image holds no running processes or memory. A snapshot saves the memory and disk of a running sandbox, and a restored sandbox resumes its processes.
| Concept | Description |
|---|---|
| Registry image | An image pulled from a public or private registry and registered under a name. |
| Dockerfile build | An image Daytona builds from Dockerfile text, with or without a build context. |
| Capture | An image made from the filesystem of a running Linux or Windows sandbox. |
| Windows base image | A base image Daytona provides for Windows sandboxes. It boots in every region. |
| Anonymous image | An image without a name. Daytona deletes it after it goes unused for its idle window. |
| Status | pending, building, ready, or failed. Sandboxes boot only from a ready image. |
| Home region | The region where Daytona builds, pulls, or captures the image. |
Use cases
Images are used when many sandboxes need the same software, files, or configuration.
- Preinstalled dependencies: packages, language runtimes, and tools are installed once in a Dockerfile build, and every sandbox from the image starts with them.
- Shared environments: a named image gives every sandbox in a project the same filesystem and start configuration under one name.
- Pinned environments: a registry image is registered under a name, so a moved or deleted registry tag does not change what sandboxes boot.
- Configured sandboxes as templates: a sandbox set up by hand or by an agent is captured, and new sandboxes start from its filesystem.
- Private application images: images that a CI pipeline pushes to a private registry are imported with the project's registry credentials and boot in sandboxes.
- Environments written by agents: an agent writes a Dockerfile, builds it, and boots sandboxes from the result, without access to your build infrastructure.
- amd64 and arm64 builds: one Dockerfile builds for either CPU architecture, so sandboxes on both kinds of host run the same software.
- Evaluation and reinforcement learning (RL): each test case or episode starts in a new sandbox from the same image, so results do not depend on another run.
Create sandboxes from images
Create a sandbox from an image registered in the project, by its name or ID. A sandbox create does not pull from a registry, so the image is pulled, built, or captured first. Registration runs in the background, and a create from an image that is not ready yet fails.
from daytona import Daytona
daytona = Daytona()
# Register python:3.12-slim under the name python-3.12
image = daytona.v2.images.pull("python:3.12-slim", name="python-3.12")
# Each wait returns after 30 seconds at most; a create from an image that is not ready fails
while image.status not in ("ready", "failed"):
image = daytona.v2.images.get(image.id, wait="ready")
if image.status == "failed":
raise RuntimeError(image.error)
sandbox = daytona.v2.create("python-3.12")Inline Dockerfile
Build an image from Dockerfile text and create a sandbox from it. The SDKs do both in one call. The image is anonymous: it has no name, and the default image list does not show it. Daytona deletes an anonymous image once it goes unused for its idle window, the server maximum of 7 days by default; every sandbox create from the image restarts the window.
The Dockerfile must be self-contained. There is no build context, so instructions that copy local files have nothing to copy. Use a build context for those.
from daytona import Daytona
from daytona.v2 import ImageBuilder
daytona = Daytona()
# Builds an anonymous image from the Dockerfile, then creates the sandbox from it
sandbox = daytona.v2.create_from_build(
ImageBuilder.from_dockerfile("FROM python:3.12-slim\nRUN pip install requests\n")
)| Parameter | Type | Description |
|---|---|---|
wait | int | Sets one time budget in seconds for the build and the create together. A build that runs longer fails with 408 REQUEST_TIMEOUT. Raise the value for longer builds, or pass 0 to remove the limit. The default is 60. |
idle | int | Sets the idle window of the image in seconds. It applies only to the image. |
region | str | Selects the region for both the build and the sandbox. |
Windows images
Create a Windows sandbox from a Windows image. Windows sandboxes boot only from Windows images: a platform base image, which boots in every region, or a Windows image captured in the project, which boots only in the region it lives in.
curl 'https://api.daytona.com/sandboxes/windows' \
--request POST \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{ "image": "win2022" }'| Field | Type | Description |
|---|---|---|
image | string | Sets the Windows image by name or ID. The image is a platform base image or a Windows image captured in the project. This field is required. |
Pull images
Pull an image from a registry and register it under a name. The pull runs in the background, and the call returns once it is queued. Pulling again under the name of an existing registry or Dockerfile image re-imports the image: it returns to pending, and sandbox creates from it fail until the new pull is ready. A private registry authenticates with the registry credential stored for the image host.
from daytona import Daytona
daytona = Daytona()
image = daytona.v2.images.pull("ghcr.io/acme/agent:v3", name="my-awesome-image")| Parameter | Type | Description |
|---|---|---|
name | str | Sets the image name. The name is 1 to 128 characters of letters, digits, ., _, and -. It must not start with ., snap-, build-, refs, by-digest, or prj-. It must not look like an image ID, img_.... Images and snapshots share one name space per project. A name that belongs to a captured image, a Windows image, or a snapshot returns 409. Without a name, the image is anonymous. An anonymous pull reuses an existing pending, building, or ready anonymous image of the same reference in the same region. |
Build images
Build an image from a Dockerfile and register it under a name. The build runs in the background: the call returns once it is queued, and the image can be used once it is ready.
Builds are deduplicated within a project and region. Submitting the same Dockerfile and build context for the same CPU architecture reuses the earlier build instead of running a new one; if that build already finished, the new image is ready at once.
from daytona import Daytona
from daytona.v2 import ImageBuilder
daytona = Daytona()
image = daytona.v2.images.build(
ImageBuilder.from_dockerfile("FROM python:3.12-slim\nRUN pip install requests"),
name="my-awesome-image",
)| Parameter | Type | Description |
|---|---|---|
name | str | Sets the image name. Without a name, the image is anonymous. |
idle | int | Sets how many seconds an anonymous image can go without a sandbox create before deletion. It applies only to anonymous images. -1 sets the maximum. The default is the server maximum. |
Build context
Build an image from a Dockerfile and a build context. Daytona uploads the context with the request and runs the build in the image's home region. A build context is needed when the Dockerfile copies local files. Without one, the Dockerfile is sent as text, as in build images.
# The context holds the Dockerfile at its root
daytona image build my-awesome-image --context context.tar| Flag | Type | Description |
|---|---|---|
--context | string | Sets the build context, a tar archive or a directory. The packed context is at most 64 MiB. This flag is required. |
--dockerfile | string | Sets the path of the Dockerfile inside the context. The default is Dockerfile. |
--timeout | string | Sets how long the command waits for the build to finish. The default is 10m. |
--no-wait | boolean | Returns once the build is queued, without waiting for it to finish. |
Build options
Build accepts an optional home region and CPU architecture. Pull accepts only a home region and always uses the region's architecture. The same Dockerfile built for two architectures produces two separate images.
from daytona import Daytona
from daytona.v2 import ImageBuilder
daytona = Daytona()
image = daytona.v2.images.build(
ImageBuilder.from_dockerfile("FROM python:3.12-slim\nRUN pip install requests"),
name="my-awesome-image",
region="us",
cpu_arch="arm64",
)| Parameter | Type | Description |
|---|---|---|
region | str | Sets the home region of the image. The default is the resolved default region for the project, organization, or platform. |
cpu_arch | str | Sets the CPU architecture to build for, amd64 or arm64. The pull methods accept only region, not cpu_arch. A from_registry builder with no steps is also a pull, so cpu_arch does not apply to that builder either. The default is the region's architecture. |
Declarative builds
Describe an image in code instead of writing a Dockerfile. Start from a registry image, chain the steps the image needs, and build it like any other image. Each step adds one Dockerfile instruction, and the SDK renders the Dockerfile when the build is submitted.
Both SDKs render the same Dockerfile for the same steps, so a build submitted from Python and the same build submitted from TypeScript are deduplicated into one image. A sandbox booted from the image gets its environment variables and runs its entrypoint and command in its working directory, or in the user's home directory when the image sets none or sets the root directory. The image's user does not carry over: sandboxes run as root unless a user is set when the sandbox is created.
from daytona import Daytona
from daytona.v2 import ImageBuilder
daytona = Daytona()
builder = (
ImageBuilder.from_registry("python:3.12-slim")
.pip_install("requests", "numpy>=1.26")
.run_commands("mkdir -p /app/data")
.env({"LOG_LEVEL": "debug"})
.workdir("/app")
)
image = daytona.v2.images.build(builder, name="my-awesome-image")| Method | Type | Description |
|---|---|---|
from_registry | str | Sets the registry image reference to start from, rendered as FROM. A builder from from_registry with no steps is a registry import, not a build. images.build pulls that image as pull images does. from_dockerfile starts from Dockerfile text instead, and the steps are appended after that text. This method is required unless the builder starts from from_dockerfile. |
pip_install | *str | Adds Python packages as one RUN python -m pip install step. Each package is shell-quoted, so a version specifier such as numpy>=1.26 stays one argument. |
run_commands | *str | Adds shell commands as one RUN step per command. |
env | str, str or Mapping[str, str] | Sets one variable as a name and a value, or several as a mapping. Each variable is rendered as one ENV step. |
workdir | str | Sets the working directory, rendered as WORKDIR. |
Preview the Dockerfile
Render the Dockerfile a builder describes and the request body it produces, without submitting a build. Use it to review the generated instructions, or to send the build yourself through the API.
from daytona.v2 import ImageBuilder
builder = ImageBuilder.from_registry("python:3.12-slim").pip_install("requests")
print(builder.render_dockerfile())
# FROM python:3.12-slim
# RUN python -m pip install requests
source, dockerfile = builder.build_request_source()Capture images
Capture the filesystem of a running sandbox as an image. The sandbox keeps running, and new sandboxes boot from the image. The capture runs in the background: the image starts as pending and becomes ready when the capture finishes. Linux and Windows sandboxes can be captured; a GPU sandbox saves its state as a checkpoint instead, and a macOS sandbox cannot be captured.
A named capture is permanent until you delete it. An unnamed capture is anonymous and is deleted once unused for its idle window, the server maximum of 7 days by default; every sandbox create from the image restarts the window. To keep an anonymous capture, promote it.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create("python-3.12")
sandbox.process.run("pip install requests")
image = sandbox.snapshot_filesystem(name="my-env")
# Wait until the capture is ready, then boot new sandboxes from it
while image.status not in ("ready", "failed"):
image = daytona.v2.images.get(image.id, wait="ready")
if image.status == "failed":
raise RuntimeError(image.error)
clone = daytona.v2.create("my-env")| Parameter | Type | Description |
|---|---|---|
name | str | Sets the image name, which must be unique in the project. The default is None, which makes the image anonymous. |
idle | int | Sets how many seconds an anonymous image can go without a sandbox create before deletion. It applies only to anonymous images. -1 sets the maximum. The default is the server maximum. |
Promote images
Promote an anonymous image by giving it a name. A promoted image is permanent: it is no longer deleted after its idle window, and the default image list shows it. Promotion works only on anonymous images; an image that already has a name cannot be renamed.
from daytona import Daytona
daytona = Daytona()
image = daytona.v2.images.promote("{imageId}", "my-env")
print(image.name)| Parameter | Type | Description |
|---|---|---|
image_id | str | Identifies the image by its ID, img_.... This parameter is required. |
name | str | Sets the image name, which must be unique in the project. This parameter is required. |
Convert images
Convert an image to the current image format before its first use. Images registered by the migration from Daytona v1 are stored in an older format until they are converted. Such an image converts on its first Linux sandbox create, which waits in the queued state while the conversion runs. GPU sandboxes, Windows sandboxes, and builds that name the image as their source refuse it until it is converted. Converting ahead of time removes the wait from the first create and makes the image usable everywhere.
curl 'https://api.daytona.com/images/{imageId}/convert' \
--request POST \
--header 'Authorization: Bearer YOUR_API_KEY'
# Returns on ready or failed, or after timeout_ms; repeat while status is pending or building
curl 'https://api.daytona.com/images/{imageId}?wait=ready&timeout_ms=60000' \
--header 'Authorization: Bearer YOUR_API_KEY'The response has the following fields:
| Field | Description |
|---|---|
converted | The value is true when the call started a conversion or joined one in progress. The value is false when the image is already in the current format and nothing was queued. |
Operations
List images
List images in the project, newest first. The list returns named images by default. Anonymous images, such as the ones inline Dockerfile builds create, appear only when you ask for them.
from daytona import Daytona
daytona = Daytona()
page = daytona.v2.images.list()
for image in page.items:
print(image.name, image.status)| Parameter | Type | Description |
|---|---|---|
anonymous | bool | Literal["any"] | Selects which images to list. True returns anonymous images only, and "any" returns both named and anonymous images. The default is False. |
limit | int | Sets the page size, clamped to 1 through 200. The default is 100. |
Each image has the following fields:
| Field | Description |
|---|---|
id | Image ID (img_...), used by the get, promote, convert, build-logs-url, and delete endpoints; returned as image_id when the image is created |
name | The name sandboxes reference through image |
status | pending, building, ready, or failed |
error | Build failure reason; null unless status is failed |
source | The build source as submitted: a registry reference, a named image, or a Dockerfile context; null for captured images |
region | Home region the image was built or pulled in |
available_in | Regions that hold a copy of the image right now; the home region is listed only while its own copy is there. Empty until the build finishes and after every copy is evicted |
manifest_name | Name of the converted image manifest; null until the build completes |
bytes | Size of the converted image in bytes; null until the build completes |
layer_count | Number of layers in the converted image |
format_version | Storage format of the image: 1 for images registered by the migration from Daytona v1, 2 for the current format |
format_outdated | true when format_version is below the current format; convert the image before use outside Linux sandboxes |
created_at | Creation timestamp |
cursor | Token to resume the list immediately after this row; returned by list only |
Iterate over all images
Iterate over every image in the project without handling page cursors. The iterator requests the next page when the current page is exhausted.
from daytona import Daytona
daytona = Daytona()
for image in daytona.v2.images.iter():
print(image.name, image.status)Get an image
Get an image by its ID. The response carries the image fields described under list images, including its status and failure reason. A name is not accepted; to find an image by name, filter the image list by name.
from daytona import Daytona
daytona = Daytona()
image = daytona.v2.images.get("{imageId}")
print(image.name, image.status)Check the image cache
Check whether a registry image is already converted and cached. The image cache is the shared store of converted registry images and their layers. It is not scoped to a project, so it does not show which images a project has registered; list images for that.
# Is a registry reference already converted and cached?
daytona image cache list --ref python:3.12-slim| Flag | Type | Description |
|---|---|---|
--ref | string | Sets the registry reference to check. The command then reports the image and whether each of its layers is cached. Without --ref, the command lists cached images one page at a time. |
--all | bool | Follows every page. |
Delete images
Delete an image. Deletion fails while a sandbox created from the image is not deleted. A captured image also cannot be deleted while another capture, sandbox, or snapshot still uses its files.
from daytona import Daytona
daytona = Daytona()
daytona.v2.images.delete("{imageId}")Build logs
Read the output of an image build. Following the log streams output while the build runs and ends when it finishes. Stopping the reader does not stop the build.
from daytona import Daytona
from daytona.v2 import ImageBuilder
daytona = Daytona()
image = daytona.v2.images.build(ImageBuilder.from_dockerfile("FROM python:3.12-slim"), name="my-awesome-image")
daytona.v2.images.follow_build_logs(image.id, on_logs=lambda chunk: print(chunk, end=""))| Parameter | Type | Description |
|---|---|---|
timeout | float | Bounds the follow in seconds. When the timeout expires, the call raises BuildLogInterruptedError instead of returning. The cursor of the error resumes the follow. By default, there is no deadline. |
The response has the following fields:
| Field | Description |
|---|---|
reason | The reason is terminal, deadline, not_applicable, resource_deleted, or unknown. |
cursor | Resumes the follow after the last output. Pass this value in a later call. |
Build job status
Check an image build's progress. An image moves from pending to building and ends as ready or failed, with a failure reason when it fails. The API also exposes the enqueued build job.
from daytona import Daytona
daytona = Daytona()
image = daytona.v2.images.get("{imageId}")
print(image.id, image.status, image.error)