Skip to main content
Mount volumes when a sandbox needs durable shared files. You can declare volumes at sandbox create time or attach them to an already running sandbox with the SDK or HTTP API. A sandbox can have up to 8 active volume attachments. The create-time examples show the Python SDK form first and the equivalent CLI create command second. Runtime examples use the Python SDK and raw HTTP API.

Mount A Volume

from nullspace import Sandbox, Volume

volume = Volume.from_name("team-data", create_if_missing=True)

with Sandbox.create(
    template="base",
    volumes=[volume.mount("/workspace/shared")],
) as sandbox:
    sandbox.files.write("/workspace/shared/hello.txt", "persistent\n")
Mount paths must be absolute sandbox paths outside runtime-managed paths such as /workspace/.nullspace.

Mount A Subpath

Expose only one directory from the volume:
mount = volume.mount("/workspace/datasets", subpath="/datasets")
sandbox = Sandbox.create(template="base", volumes=[mount])
subpath is resolved inside the volume and exposes only that subtree at the sandbox mount path.

Read-Only Mounts

mount = volume.mount("/workspace/models", subpath="/published-models", read_only=True)
sandbox = Sandbox.create(template="base", volumes=[mount])
read_only=True prevents writes through the sandbox mount. Callers with API access can still modify the volume through direct volume.files or nullspace volume ... operations.

Dictionary Mounts

SDK calls also accept dictionaries, which is useful when mount configuration is loaded from JSON:
sandbox = Sandbox.create(
    template="base",
    volumes=[
        {
            "ref": "team-data",
            "mount_path": "/workspace/shared",
            "subpath": "/datasets",
            "read_only": True,
        },
    ],
)
ref can be a volume name or volume ID.

Runtime Attach And Detach

Attach a volume to a running sandbox with the same mount descriptor shape used at create time:
from nullspace import Sandbox, Volume

sandbox = Sandbox.connect("sb_...")
volume = Volume.from_name("team-data")

attachment = sandbox.attach_volume(volume.id, "/workspace/shared")
print(attachment.id, attachment.state, attachment.mount_path)
List the current attachments for a sandbox or a volume:
for attachment in sandbox.list_volumes():
    print(attachment.id, attachment.volume_id, attachment.state)

for attachment in volume.attachments():
    print(attachment.sandbox_id, attachment.mount_path, attachment.state)
The equivalent HTTP list routes are GET /v1/sandboxes/{id}/volumes and GET /v1/volumes/{id}/attachments. Detach one runtime attachment by ID:
released = sandbox.detach_volume(attachment.id)
print(released.state)
The Python SDK accepts a volume ID, volume name, VolumeMount, or dictionary for sandbox.attach_volume(...). If read_only is omitted, the runtime API defaults it to false.

Health And Remount

Use health and remount operations when a mounted volume is degraded or after an operator asks you to refresh the live mount:
health = sandbox.get_volume_health(attachment.id)
if health.state == "failed":
    print(health.last_error_code, health.last_error_message)

remounted = sandbox.remount_volume(attachment.id)
print(remounted.state)
Attachment states include requested, mounting, mounted, paused, remounting, unmounted, releasing, released, and failed. Destroy the sandbox to release all remaining volume attachments. Hibernating or pausing a sandbox releases the live mount lease while the VM is stopped, but it preserves the attachment intent; resume remounts the same volumes. Fork and snapshot restore also remount the stored attachments in the new sandbox. The CLI currently supports create-time --volume entries. Use the SDK or HTTP API for runtime attach, detach, health, and remount operations.

Snapshot Behavior

Shared volume data is durable storage external to VM memory and mutable rootfs snapshots. Hibernate, resume, and fork remount volume attachments; they do not copy volume data into the VM snapshot.