Sandboxes

Volumes

A persistent volume is a named disk that survives a sandbox and follows you to the next one. Attach it and it mounts at /persist - anything you write there is still there when a later sandbox attaches the same volume. It's how you keep data (caches, model weights, a working directory, a database file) across otherwise-ephemeral sandboxes.

The short version
  • Sandbox.create(volume="my-data") mounts the volume at /persist.
  • Write under /persist - it persists across terminate.
  • Re-use the same volume name in a later sandbox to get the data back.
  • Created on first use (default 10 GB); one running sandbox per volume at a time.

/persist vs /workspace

A sandbox has two writable places, and the difference is the whole point:

  • /workspace (and /tmp) - fast scratch, but RAM-backed. Gone the moment the sandbox terminates, and it counts against the sandbox's memory.
  • /persist - a real disk (ext4) backed by a volume. Survives terminate and re-attaches to a later sandbox. Only present when you attach a volume.

So: use /workspace for throwaway working files, and /persist for anything you want to keep.

Attach a volume

Name a volume when you create a sandbox. If it doesn't exist yet it's created on first reference (default 10 GB), so you rarely need to make one up front.

persist
from orkestr import Sandbox

# Name a volume in create() and it's attached at /persist. It's created on
# first use (default 10 GB), so you don't have to make it up front.
sbx = Sandbox.create(template="python-3.12", volume="my-data")
sbx.run("echo 'trained weights v1' > /persist/model.txt")
sbx.terminate()

# Hours or days later, a brand-new sandbox re-attaches the same volume:
sbx = Sandbox.create(template="python-3.12", volume="my-data")
print(sbx.run("cat /persist/model.txt").stdout)  # -> trained weights v1
print(sbx.volume)                                  # -> "my-data"

Manage volumes explicitly

You only need this to set a custom size, list what you have, or delete one - attaching by name already creates it.

volumes
from orkestr import Volume

# Explicit control - custom size, a region pin, listing, cleanup:
vol = Volume.create("datasets", size_gb=50, region="rbx")
for v in Volume.list():
    print(v.name, v.size_mb, v.status, v.region)   # status: ready | attached
Volume.move(vol.id, "hel1")   # re-home a detached volume to another region
Volume.delete(vol.id)   # rejected while attached to a running sandbox

How it works

One writer at a time

A volume can back only one running (or paused) sandbox at a time. Attaching a volume that's already in use returns a 409 volume_in_use - terminate the holder first. This is deliberate: an ext4 filesystem mounted read-write by two VMs at once would corrupt. When a sandbox terminates (or expires), its volume is released back to available and you can re-attach it.

Durability & where the data lives

The volume's live data is a disk on the sandbox host (fast, local). On detach and on a periodic timer, it's also checkpointed to EU object storage - so the data is durable against a host failure, and a later sandbox can pick the volume up even on a different host (it hydrates from the checkpoint). A running sandbox reads and writes the local disk directly; the checkpoint happens out of band.

Consistency
A same-box reattach always sees your latest writes - it reads the volume's disk directly. On terminate the volume is released right away and its durable copy is refreshed a moment later (out of band); otherwise the durable copy is as fresh as the last periodic checkpoint. For a working cache or checkpointed results this is exactly what you want; don't treat a volume as a transactional database's only home.

Size & pricing

size_gb is the provisioned capacity (default 10, max 100). Storage bills as GB-month at that provisioned size for as long as the volume exists, whether or not it's full - so request what you need, not the max. It shares the same storage meter, free allowance, and pay-as-you-go invoice as paused-sandbox snapshots and custom templates. Each plan caps the number of volumes and the total provisioned GB; call get_sandbox_limits (or GET /v1/sandboxes/limits) to see max_volumes / max_volume_gb for your tier.

Region & placement

A volume lives in one region, and a sandbox attaching it runs there too. You choose the region in either direction: pass region when you create the volume explicitly, or just create your first sandbox with a region and name a new volume - the volume homes wherever that sandbox lands. After that, attaching the volume places the sandbox in its region; passing a different region on create is rejected with a clear error rather than silently moving your sandbox.

To relocate a volume, move it while detached (Volume.move / POST /v1/sandboxes/volumes/{id}/move): the data is checkpointed to object storage and the volume re-materializes in the target region on its next attach. And if the volume's host is ever unavailable, the control plane hydrates it onto another host from the checkpoint automatically.

Console

Volumes show up on the Sandboxes page under Volumes - each with a mounted / available state - and on a sandbox's detail page next to its resources. You can create and delete them there, and pick one to attach when you create a sandbox from the console.

Next steps