Skip to main content
Upload directly to volumes when data should persist independently of any single sandbox. Destinations are absolute volume-internal paths rooted at /.

Upload A File

result = volume.files.upload_file(
    "./model.bin",
    "/models/model.bin",
    resumable=True,
    checksum="auto",
    max_concurrency=4,
)
print(result.bytes_uploaded, result.target_path)

Upload A Directory

result = volume.files.upload_dir(
    "./datasets",
    "/datasets",
    conflict="merge",
    ignore_patterns=["*.tmp"],
    max_concurrency=4,
)
print(result.file_count)
Directory uploads support conflict=, ignore_patterns=, and max_concurrency=.

Dispatch By Source Type

volume.files.upload("./model.bin", "/models/model.bin")
volume.files.upload("./datasets", "/datasets")
upload() dispatches to upload_file() or upload_dir() based on the local source type. Use the explicit helpers when you need file-only or directory-only options.

Resumable Uploads

from nullspace import FileUploadError

try:
    volume.files.upload_file("./large.bin", "/models/large.bin", resumable=True)
except FileUploadError as exc:
    if exc.upload_id is None:
        raise
    volume.files.resume_upload(exc.upload_id, "./large.bin")
File uploads support resumable transfer options such as --resumable, --checksum, --spool-to-disk, and --concurrency.

Upload From Stdin

tar -czf - ./dataset | nullspace volume upload team-data - /archives/dataset.tar.gz
Stdin uploads require a concrete destination file path, not a directory suffix. Resumable stdin uploads require local spooling with --spool-to-disk auto or always.

Dry Run

nullspace volume upload team-data ./datasets /datasets --dry-run --json
Dry runs preview the effective upload plan without sending data.

Signed Upload URL

grant = volume.files.upload_url("/models/model.bin")
print(grant.url, grant.method, grant.headers)
Use signed URLs when a browser, CI job, or another service should upload bytes directly.