Sign Up

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.

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.

ConceptDescription
Registry imageAn image pulled from a public or private registry and registered under a name.
Dockerfile buildAn image Daytona builds from Dockerfile text, with or without a build context.
CaptureAn image made from the filesystem of a running Linux or Windows sandbox.
Windows base imageA base image Daytona provides for Windows sandboxes. It boots in every region.
Anonymous imageAn image without a name. Daytona deletes it after it goes unused for its idle window.
StatusPending, building, ready, or failed. Sandboxes boot only from a ready image.
Home regionThe 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. A repeat build of the same Dockerfile and build context reuses the earlier build instead of running a new one. A Dockerfile that copies local files needs a build context of at most 1 GiB.

  • Configured sandboxes as templates. A sandbox set up by hand or by an agent is captured, and new sandboxes start from its filesystem. The source sandbox keeps running during the capture. A named capture stays until you delete it.

  • 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. Pulling again under the same name re-imports the image, and creates from it fail until the new pull is ready. The API call returns once the pull is queued, and the SDKs and the CLI wait by default until the image is ready.

  • Environments written by agents. An agent writes a Dockerfile, builds it, and boots sandboxes from the result, without access to your build infrastructure. The SDKs build the image and create the sandbox in one call. A failed build creates no sandbox.

  • 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. An image holds no running processes or memory, so each run boots from the same files. Runs that need processes already running start from a snapshot instead, which saves memory and disk.

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. If the same Dockerfile was built before under a name, the sandbox starts from that named image instead. 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 window starts when the image is created, so a window shorter than the build deletes the image before it is ready.

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")
)
ParameterTypeDescription
build_timeoutfloatSets how many seconds the build can take. A build that runs longer fails with 408 REQUEST_TIMEOUT and creates no sandbox. The build keeps running, and its anonymous image is deleted after its idle window. By default, or with 0, there is no limit.
wait_secondsintSets how many seconds the create waits for the sandbox to start, as in create. It does not limit the build. The default is 60.
idle_expiry_secondsintSets the idle window of the image in seconds. It applies only to the image. It is ignored when the build reuses the build of a named image.
regionstrSelects 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" }'
FieldTypeDescription
imagestringSets 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. The API call returns once the pull is queued, and the SDKs and the CLI wait until the image is ready by default. Pulling again under the name of an existing registry or Dockerfile image re-imports the image: it keeps its ID, returns to pending, and sandbox creates from it fail until the new pull is ready. A failed pull keeps its name, so pull again under the name to retry. A private registry authenticates with the registry credential stored for the image host.

from daytona import Daytona

daytona = Daytona()

image = daytona.v2.images.pull("node:22-slim", name="my-awesome-image")
ParameterTypeDescription
namestrSets the image name. The name is 1 to 128 characters of letters, digits, ., _, and -. It must not start with ., sbx_, vol_, fn_, snap-, build-, refs, by-digest, prj-, or glb-. It must not have the format of an image ID, img_.... 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. 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.

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. A build without a name that reuses the build of a named image returns that named image, which stays permanent.

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",
)
ParameterTypeDescription
namestrSets the image name. Without a name, the image is anonymous, unless the build reuses the build of a named image; the call then returns that named image.
idle_expiry_secondsintSets how many seconds an anonymous image can go without a sandbox create before deletion. -1 sets the maximum. The default is the server maximum. It is allowed only without name. It is ignored when the build reuses the build of a named image. When the build reuses an anonymous image, that image keeps the longer of the two windows.

Build context

Build an image from a Dockerfile and a build context. Daytona uploads the context to the image's home region and runs the build there. A build context is needed when the Dockerfile copies local files. Without one, the Dockerfile is sent as text, as in build images. The SDKs and the CLI upload a context of up to 1 GiB.

from daytona import Daytona

daytona = Daytona()

# The context holds the Dockerfile at its root
image = daytona.v2.images.build_from_context("context.tar", name="my-awesome-image")
ParameterTypeDescription
contextbytes or strSets the build context: the bytes of a tar archive, or the path of a .tar file. The archive is at most 1 GiB. This parameter is required.
dockerfilestrSets the path of the Dockerfile inside the context. The default is Dockerfile.
namestrSets the image name. Without a name, the image is anonymous, unless the build reuses the build of a named image; the call then returns that named image.
idle_expiry_secondsintSets how many seconds an anonymous image can go without a sandbox create before deletion. The default is the server maximum. It is allowed only without name. It is ignored when the build reuses the build of a named image. When the build reuses an anonymous image, that image keeps the longer of the two windows.

Large build contexts

Upload a build context of up to 1 GiB and build an image from it. The upload declares the archive by its size and SHA-256, sends the archive in parts straight to storage, and is then completed. Completing the upload verifies the stored archive: its size and SHA-256 must match the declared ones, it must be a well-formed tar archive, and its Dockerfile must be accepted for a build. An archive that fails verification is deleted.

An upload belongs to one region, and only a build in that region can use it. When the project already holds a verified upload of the same archive in the region, Daytona returns that upload and the archive is not sent again. The SDKs and the CLI run these steps when they upload a build context.

# Size in bytes and SHA-256 of the archive (on macOS use: shasum -a 256 context.tar)
wc -c < context.tar
sha256sum context.tar

# Declare the upload: replace 10240 with the size from wc and {sha256} with the hash from sha256sum
curl 'https://api.daytona.com/build-contexts' \
  --request POST \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "bytes": 10240,
  "sha256": "{sha256}"
}'

# Split the archive into parts of part_size bytes: part 1 is part-aa, part 2 is part-ab, and so on
split -b {partSize} context.tar part-

# Upload each part to its url, without an Authorization header
curl '{partUrl}' --upload-file part-aa

# Verify the uploaded archive
curl 'https://api.daytona.com/build-contexts/{uploadId}/complete' \
  --request POST \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "region_id": "{regionId}"
}'

# Build from the verified upload
curl 'https://api.daytona.com/images' \
  --request POST \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "my-awesome-image",
  "context_upload_id": "{uploadId}"
}'
FieldTypeDescription
bytesintegerSets the size of the archive in bytes, from 1 to 1073741824 (1 GiB). This field is required.
sha256stringSets the SHA-256 of the archive, as 64 lowercase hex characters. This field is required.
dockerfilestringSets the path of the Dockerfile inside the context. The default is Dockerfile.
region_idstringIn the declare request, sets the region of the upload. The default is the resolved default region. In the complete request, it is the region_id the declare request returned. This field is required in the complete request.
context_upload_idstringSets the ready upload to build. The image must be created in the region of the upload. It cannot be combined with dockerfile or source.
namestringSets the image name. Without a name, the image is anonymous, unless the build reuses the build of a named image; the call then returns that named image.

The declare and complete requests return the upload, with the following fields:

FieldDescription
idIdentifies the upload.
region_idThe region the upload belongs to.
stateThe state is uploading until the upload is completed and verified, then ready.
part_sizeThe size of every part but the last, in bytes. It is set while the upload is uploading.
partsThe parts to upload, each with its part_number, its size in bytes, and its url. It is empty once the upload is ready.
urls_expire_atThe time the part URLs stop accepting uploads.
upload_expires_atThe time an upload that was not completed expires and is deleted.
expires_atThe time a ready upload can no longer be used by a build.

Build options

Build accepts an optional home region and CPU architecture. Pull accepts 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-east",
    cpu_arch="amd64",
)
ParameterTypeDescription
regionstrSets the home region of the image. Earth and country-wide regions such as us return an error. The default is the resolved default region for the project, organization, or platform.
cpu_archstrSets the CPU architecture to build for, amd64 or arm64. A build for an architecture that no runner in the region provides stays pending. images.pull also accepts cpu_arch, but a pull ignores the value and uses the region's architecture. A from_registry builder with no steps ignores the value the same way. 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. A sandbox runs as the image's user, or as root when the image sets none, sets root, or sets a numeric user ID. A user set when the sandbox is created replaces the image's user.

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")
MethodTypeDescription
from_registrystrSets 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*strAdds 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*strAdds shell commands as one RUN step per command.
envstr, 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.
workdirstrSets the working directory, rendered as WORKDIR.

Preview the Dockerfile

Render the Dockerfile a builder describes, without submitting a build. Use it to review the generated instructions, or to send the build yourself through the API as the dockerfile field of POST /images.

from daytona.v2 import ImageBuilder

builder = ImageBuilder.from_registry("python:3.12-slim").pip_install("requests")

print(builder.to_dockerfile())
# FROM python:3.12-slim
# RUN python -m pip install requests

Capture images

Capture the filesystem of a sandbox as an image, and boot new sandboxes from the image. The capture runs in the background, and the image becomes ready when the capture finishes. Linux and Windows sandboxes are captured while running, and they keep running. A macOS sandbox is captured when it is persistent and stopped, as a filesystem snapshot. A GPU sandbox saves its state as a checkpoint instead.

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()
sandbox.process.run("pip install requests")

image = sandbox.capture_image(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")
ParameterTypeDescription
namestrSets the image name. The default is None, which makes the image anonymous. The name must be unique in the project.
idle_expiry_secondsintSets how many seconds an anonymous image can go without a sandbox create before deletion. -1 sets the maximum. The default is the server maximum. It is allowed only without name.

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)
ParameterTypeDescription
image_idstrIdentifies the image by its ID, img_.... This parameter is required.
namestrSets the image name. This parameter is required. The name must be unique in the project.

Convert images

Convert an image to the current image format before its first use. Images registered by the migration from Daytona v0 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:

FieldDescription
idIdentifies the image.
convertedThe 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.
from_formatThe format_version of the image before the call.
to_formatThe format the conversion targets, the current one.
statusThe image status after the call: pending or building while the image converts, or its own status when it is already in the current format.

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)
ParameterTypeDescription
anonymousboolSelects which images to list. True returns anonymous images only, and False returns named images only. The default is False.
limitintSets the page size, from 1 to 200. The default is 100.
cursorstrResumes the list after the previous page. Pass the next_cursor of that page, which is set when more images exist.
namestrFilters the list by exact image name.
sandbox_idstrLists only the captures taken from this sandbox.
platformstrSelects platform images, which Daytona publishes for every project. "true" lists platform images only, "false" lists the project's images only, and "any" lists both. The default is "false".

Each image has the following fields. The SDKs return region_id as region, region_ids as available_in (availableIn in TypeScript), and class as sandbox_class (sandboxClass in TypeScript).

FieldDescription
idImage ID (img_...), used by the get, promote, convert, build-logs-url, and delete endpoints; returned as id when the image is created
nameThe name sandboxes reference through image
statuspending, building, ready, or failed
errorBuild failure reason; null unless status is failed
sourceThe build source as submitted: a registry reference, a named image, or a Dockerfile context; null for captured images
originHow the image was created, such as registry, dockerfile, or capture
classSandbox class the image supports, such as linux or macos
anonymoustrue when the image has no name
retentionpermanent for a named image, idle for an anonymous image
expires_atWhen an anonymous image is deleted unless a sandbox create restarts its idle window; null for a permanent image
region_idHome region the image was built, pulled, or captured in
region_idsRegions 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
platformtrue for a platform image that Daytona publishes for every project
defaulttrue for the image that a sandbox create without an image boots
deprecatedtrue for a deprecated platform image, which is not listed and cannot be used by name; its ID still resolves
bytesSize of the converted image in bytes; null until the build completes
layer_countNumber of layers in the converted image
disk_mibDisk size in MiB of a macOS sandbox created from the image without disk_mib, and the smallest disk such a create accepts; set for images captured from a macOS sandbox, null otherwise
format_versionStorage format of the image: 1 for images registered by the migration from Daytona v0, 2 for the current format
format_outdatedtrue when format_version is below the current format; convert the image before use outside Linux sandboxes
imported_fromSource platform and resource ID of an image imported by the migration from Daytona v0, as {"platform": "v0", "id": "..."}; absent for an image created on Daytona v2
created_atCreation timestamp
updated_atTimestamp of the last change
cursorToken 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 or name. The response carries the image fields described under list images, including its status and failure reason.

from daytona import Daytona

daytona = Daytona()

image = daytona.v2.images.get("{imageId}")
print(image.name, image.status)

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\nRUN pip install requests"),
    name="my-awesome-image",
)
daytona.v2.images.follow_build_logs(image.id, on_logs=lambda chunk: print(chunk, end=""))
ParameterTypeDescription
on_logsCallableReceives the build output as text. Without on_event, it also receives one line per state change and per gap, unavailable, source_changed, or error event, prefixed with the event type, such as [build logs: state]. This parameter is required.
on_eventCallableReceives every stream event, including state changes. With on_event, these events no longer reach on_logs.
timeoutfloatBounds 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:

FieldDescription
statusThe image status when the follow ended.
reasonThe reason is terminal, deadline, not_applicable, resource_deleted, or unknown.
output_completeThe value is true when all build output was delivered.
cursorResumes the follow after the last output. Pass this value in a later call.

Build 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.

from daytona import Daytona

daytona = Daytona()

image = daytona.v2.images.get("{imageId}")
print(image.id, image.status, image.error)

Permissions

Images are scoped to a project. Access is governed by three permissions, which you can grant to an organization role or an API key.

Creating a sandbox from an image requires the permission to create sandboxes, and capturing an image of a sandbox requires the write:sandboxes permission as well as write:images. The audit logs record image builds, captures, promotions, conversions, and deletes.

PermissionGrants
read:imagesList and get images, and read their build logs
write:imagesBuild, pull, capture, promote, and convert images
delete:imagesDelete images