Nullspace persistence is built around hibernate and resume. Hibernate stops the active VM and records a paused-machine snapshot; resume restores that state into a runnable machine. This is separate from reusable snapshots, which keep the source machine running and can be used as a 1-to-many starting point.

Pause a machine

from nullspace import Machine

machine = Machine.create(template="base")
machine.files.write("/workspace/report.txt", "draft\n")
snapshot = machine.pause()
print(snapshot.id)
import { Machine } from "@nullspace/sdk";

const machine = await Machine.create({ template: "base" });
await machine.files.write("/workspace/report.txt", "draft\n");
const snapshot = await machine.pause();
console.log(snapshot.id);
nullspace machine pause mch_123   # alias for hibernate; returns the snapshot id
curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/hibernate" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"

Resume paused state

resumed = Machine.resume(machine.id)
print(resumed.files.read("/workspace/report.txt"))
resumed.kill()
import { NullspaceClient } from "@nullspace/sdk";

const client = new NullspaceClient();
const resumed = await client.snapshots.resume(snapshot.id);
console.log(await resumed.files.read("/workspace/report.txt"));
await resumed.destroy();
nullspace machine resume mch_123
curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/resume" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"
Resume restores the original paused machine ID. If the original machine paused because of timeout behavior, Machine.connect(original_id) and public auto-resume traffic use that same ID after the machine is running again.
original_id = machine.id
snapshot = machine.pause()

resumed = Machine.connect(original_id)
print(original_id, resumed.id)
const originalId = machine.id;
const snapshot = await machine.pause();

const resumed = await Machine.connect(originalId);
console.log(originalId, resumed.id);
nullspace machine pause mch_123
nullspace machine get mch_123   # the original id resolves to the latest execution
curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/hibernate" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"

curl "${NULLSPACE_API_URL}/v1/machines/mch_123" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"

Reusable snapshots

snapshot = machine.create_snapshot()

child_a = Machine.create(snapshot_id=snapshot.id)
child_b = Machine.create(snapshot_id=snapshot.id)

child_a.kill()
child_b.kill()
const snapshot = await machine.createSnapshot();

const childA = await Machine.create({ snapshotId: snapshot.id });
const childB = await Machine.create({ snapshotId: snapshot.id });

await childA.destroy();
await childB.destroy();
nullspace snapshot create mch_123   # returns a reusable snapshot id
nullspace machine create --snapshot-id snap_123
nullspace machine create --snapshot-id snap_123
curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/snapshots" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"

curl -X POST "${NULLSPACE_API_URL}/v1/machines" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"snapshot_id": "snap_123"}'
create_snapshot() briefly pauses the source, captures memory and mutable rootfs state, resumes the source, and returns a reusable snapshot ID. Use Machine.create(snapshot_id=...) to spawn independent children from it.

Behavior

  • VM memory and mutable rootfs state come from hibernate or reusable snapshots.
  • Shared volumes are remounted as external storage during resume and fork.
  • Snapshot compatibility depends on runtime host and kernel compatibility; incompatible restores fail explicitly instead of silently starting from scratch.
  • Machine.get_info_by_id(id) is read-only and does not wake a paused alias.
  • Deleting a paused original ID removes the paused alias and its lifecycle routing target.
  • Use lifecycle events to observe transition state and recovery failures.

Auto-resume

Create with on_timeout="pause", auto_resume=True when a public HTTP or WebSocket request should wake a paused machine before the request is forwarded. When the wake cannot complete in time, callers get 503 Service Unavailable with Retry-After: 5.