Persistence
Sandbox filesystem and memory persistence.
Daytona sandboxes are ephemeral by default: the writable filesystem lives on host-local storage and exists only while the sandbox does. Setting the persistent parameter to true at create time moves the write layer onto durable network-backed storage. A persistent sandbox keeps its identity, filesystem, and configuration across stop and start, survives host failure, and is deleted only when you delete it, mark it as ephemeral (default), or set an auto-delete interval.
| Layer | What is preserved | Mechanisms |
|---|---|---|
| Filesystem | Files, packages, repositories, build artifacts | • Persistence • Stop / start • Image capture |
| Memory | Processes, connections, states | • Pause / resume • Snapshots • Fork |
| External storage | Data that outlives any single sandbox | • Volumes |
Use cases
Persistence is used when the state of a sandbox must survive past one session.
- Development environments: a sandbox keeps its repositories, packages, and configuration across stop and start. Nothing has to be reinstalled or rebuilt.
- Agent workspaces: an agent stops work and continues later in the same sandbox, with the files it wrote still in place.
- Long computations: a pause keeps running processes, open connections, and memory, and a resume continues them instead of a restart.
- Idle cost control: an idle persistent sandbox stops or pauses on its idle timeout instead of running or being deleted. It starts again on an explicit start or resume. A Linux sandbox with
wake_on_requestset also starts on the next request. A stopped sandbox costs nothing in compute, and only its storage is billed. - Host failures: the write layer lives on network-backed storage, so a persistent sandbox survives the loss of its host. The sandbox becomes stopped and starts again on healthy hardware.
- Risky changes on a copy: a fork duplicates the filesystem and memory of a sandbox into an independent sandbox. A risky change or a divergent experiment runs on the copy, and the original stays as it was.
- Runs from a known state: a fork or a snapshot copies a configured sandbox, so several runs or every agent in a fleet start from the same state.
- Spot sandboxes worth continuing: a reclaim pauses or stops a persistent spot sandbox instead of deleting it. The work continues after a resume or a start.
Filesystem persistence
Filesystem persistence keeps the contents of a sandbox's disk: files, installed packages, cloned repositories, and build artifacts. A sandbox with a preserved filesystem starts with its environment intact, with nothing to reinstall or rebuild.
| Sandbox type | Filesystem persistence |
|---|---|
| Ephemeral (default) | Write layer on host-local storage; it exists only while the sandbox does. There is no stop or pause: delete discards the filesystem, and a host failure loses the sandbox. Capture an image or write to a volume to keep results. |
| Persistent | Write layer on durable network-backed storage. Stop releases compute and keeps the filesystem; start boots the sandbox again, possibly on different hardware. A host failure leaves the sandbox stopped, never lost. To keep the filesystem under a name, capture an image. To keep memory as well, take a snapshot. |
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create(persistent=True)
# Write state to the filesystem
sandbox.process.run("pip install requests && echo done > /root/setup.log")
# Stop releases compute; the filesystem stays on durable storage
sandbox.stop()
sandbox.wait_for_state(["stopped"], timeout=60)
# Start boots the sandbox again, possibly on different hardware
sandbox.start()
response = sandbox.process.run("cat /root/setup.log")
print(response.stdout) # doneMemory persistence
Memory persistence keeps the runtime state of a sandbox: running processes, open connections, and everything loaded in RAM. A sandbox with preserved memory continues from the point it was frozen, with processes still running, instead of starting from a clean boot.
Memory survives pause / resume, snapshots, and forks, all of which require a persistent sandbox. A sandbox with an attached disk volume cannot pause, and one with any attached volume cannot fork; snapshots exclude volumes. Memory is cleared on every stop.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create(persistent=True)
# Launch a process that holds state in memory
sandbox.process.start("python3 -m http.server 8000")
# Pause freezes the sandbox with filesystem and memory intact
sandbox.pause()
sandbox.wait_for_state(["paused"], timeout=60)
# Resume continues all processes from the point they were frozen
sandbox.resume()
response = sandbox.process.run(
"python3 -c \"import urllib.request; print(urllib.request.urlopen('http://localhost:8000').status)\""
)
print(response.stdout) # 200: the server is still runningPersistence beyond a sandbox
Filesystem and memory persistence are tied to a single sandbox: deleting the sandbox deletes its state. To persist state beyond the sandbox itself, capture it as an image or a snapshot, duplicate it into an independent sandbox with a fork, or store data outside any sandbox in a volume.
Images and snapshots
An image capture saves the filesystem of a running Linux or Windows sandbox under a name, and new sandboxes boot from it. A snapshot saves the memory and disk of a running sandbox, and a restored sandbox resumes the captured processes. A snapshot requires a resumable source, persistent or served from a warm template, and restores only on the runner that captured it.
A snapshot covers the sandbox's own state. Attached volumes are independent resources you re-attach at restore time, and a restored sandbox gets a fresh IP and port mappings. Deleting the source sandbox does not delete its snapshots.
Forks
Forking duplicates a sandbox's filesystem and memory at one instant into a new, independent sandbox. Forks branch a live environment: run divergent experiments from the same state, try a risky change on a copy, or give each agent in a fleet the same starting point.
Volumes
Volumes are named, project-scoped storage that persists independently of any sandbox. A disk volume gives the sandbox a fast local copy whose changes commit back in the background, so data survives sandbox deletion and becomes visible to sandboxes that attach after the commit. A bucket volume mounts an S3 bucket live, so running sandboxes see each other's closed files within seconds. On both, concurrent writes to one file race; the last wins. Use volumes for datasets, model weights, build caches, and per-tenant data scoped with a subpath.
Retention and lifecycle
Stopped and paused sandboxes are retained until you delete them. A stopped persistent sandbox costs nothing in compute, but its durable storage is billed for as long as the sandbox exists, and it is never auto-pruned: delete sandboxes you no longer need. See billing for details.
Daytona does not stop, pause, or delete sandboxes on its own unless you configure a sandbox lifecycle policy. Two platform events act on sandboxes without a request from you:
- Spot reclaim: when the platform reclaims a spot sandbox, a persistent one is paused (or stopped, if it has an attached disk volume) and can be brought back later, while an ephemeral one is deleted. Reclaimed sandboxes are stamped with
spot_evicted_at. See preemption. - Host failure: a persistent sandbox on a failed host becomes
stoppedand can be started again on healthy hardware. An ephemeral sandbox on a failed host is lost.
Opting in to persistence
Ephemeral sandboxes are the default and the right choice for disposable work: they are the fastest to create and only support create and delete. Persistence costs a slower, cold-boot create and storage billing while stopped. Opt in when the sandbox is worth keeping: an environment you return to, state to pause or fork, or a workload that must survive host failure.
from daytona import Daytona
daytona = Daytona()
# Ephemeral sandboxes are the default: create, use, delete
sandbox = daytona.v2.create()
# Run the workload and read the results before deleting
response = sandbox.process.run("python3 -c 'print(1 + 1)'")
print(response.stdout)
# Delete discards the sandbox and all of its state
sandbox.delete()