Volumes are durable shared filesystems. Create them once, mount them into one or more machines, or manage their files directly through the SDK and CLI without starting a machine.
Volumes require a machine-runtime deployment with the shared-volume backend and Supabase-backed control-plane state enabled.

When To Use Volumes

NeedUse Volumes?
Persist files after a machine is destroyedYes. Volume data is external to VM memory and rootfs snapshots.
Share files across machinesYes, mount the same volume where supported by runtime configuration.
Keep live VM memory or process stateNo. Use hibernate/auto-resume for VM state.
Move large datasets in and outYes, use volume upload/download or direct volume file APIs.
Store application database stateUse a database when you need transactional semantics.

Quick Example

The Python SDK, TypeScript SDK, and CLI snippets below are equivalent ways to create a volume and mount it into a new machine. The Python SDK and CLI also show direct volume writes. Use one control plane unless you are intentionally handing a volume name or machine ID between tools.
from nullspace import Machine, Volume

volume = Volume.from_name("team-data", create_if_missing=True)
volume.files.write("/hello.txt", "persistent\n")

with Machine.create(volumes=[volume.mount("/workspace/shared")]) as machine:
    print(machine.files.read("/workspace/shared/hello.txt").strip())
import { NullspaceClient } from "@nullspace/sdk";
import type { VolumeMount } from "@nullspace/sdk";

const client = new NullspaceClient();
const volume = await client.volumes.create("team-data");

const mount: VolumeMount = {
  ref: volume.id,
  mountPath: "/workspace/shared",
};

const machine = await client.machines.create({
  template: "base",
  volumes: [mount],
});
nullspace volume create team-data
printf "persistent\n" | nullspace volume write team-data /hello.txt
nullspace machine create --template base --volume ref=team-data,mount=/workspace/shared

Mounts Vs Direct File APIs

OperationUse
Machine code reads and writes dataMount the volume into the machine.
Your controller app manages durable filesUse volume.files.* APIs directly.
Attach data to an already running machineUse runtime volume attachment.
Inspect or transfer data without computeUse volume list, read, write, upload, and download commands.

TypeScript Types

The TypeScript SDK exports the public volume shapes from @nullspace/sdk. Volume fields are camelCased in TypeScript even when the HTTP API uses snake_case.
import type {
  VolumeAttachment,
  VolumeInfo,
  VolumeMount,
} from "@nullspace/sdk";
TypeWhere You Use It
VolumeInfoReturned by client.volumes.create, get, getByName, and list.
VolumeMountPassed to client.machines.create({ volumes: [...] }) for create-time mounts.
VolumeAttachmentReturned by machine.attachVolume, machine.detachVolume, and machine.listVolumes.

Volume Tasks

Managing volumes

Create, list, inspect, field-select, and delete volume metadata.

Mounting volumes

Attach volumes at create time or runtime, including read-only and subpath mounts.

Read and write

Read, write, batch-write, move, remove, and edit direct volume files.

File and directory metadata

List directories, stat paths, check existence, search, replace, and watch changes.

Upload data

Upload files, directories, stdin streams, and resumable transfers into volumes.

Download data

Download files, directories, archives, and signed URLs from volumes.

Behavior

Shared volume data is external to VM memory and mutable rootfs snapshots. Hibernate, resume, and fork remount shared volumes; they do not make external storage part of VM memory snapshots. Runtime attachment operations return attachment records with states including requested, mounting, mounted, paused, remounting, unmounted, releasing, released, and failed. Destroying the machine releases remaining attachments. Hibernating or pausing a machine releases live mount leases while the VM is stopped, but it preserves attachment intent and remounts those volumes on resume. In hosted private beta, auto-grow is currently disabled and the default cap is 2 GiB per volume unless an operator has applied a tenant-specific override. There is no public resize API for private beta.