Skip to main content
Capture the disk state of a stopped sandbox into a portable artifact, then boot fresh sandboxes from it. See Snapshots for concepts and walkthroughs.
import { Sandbox, Snapshot, SnapshotHandle } from "microsandbox";
import type { ExportOpts, SnapshotVerifyReport } from "microsandbox";
Snapshots are disk-only and require a sandbox that is not running (stopped or crashed).

Typical flow

import { Sandbox, Snapshot } from "microsandbox";

// 1. capture: stop the sandbox, then snapshot its disk
const sb = await Sandbox.get("baseline");
await sb.stop();
const snap = await Snapshot.builder("baseline")
  .name("after-pip-install")     // bare name in the default dir
  .recordIntegrity()             // hash the upper layer
  .create();

// 2. boot a fresh sandbox from the snapshot
const fresh = await Sandbox.builder("worker")
  .fromSnapshot(snap.path)
  .create();

Capture and boot

These entry points live on SandboxBuilder and SandboxHandle; they are the bridge between sandboxes and snapshot artifacts.

.fromSnapshot()

fromSnapshot(pathOrName: string): SandboxBuilder
const sb = await Sandbox.builder("worker")
  .fromSnapshot("after-pip-install")
  .create();
Boot a fresh sandbox from a snapshot artifact. Mutually exclusive with .image(); the snapshot already pins the image. Documented in full on the Sandbox page.

Parameters

pathOrNamestring
Bare name (resolved under the default snapshots directory) or filesystem path to an artifact directory.

Returns

The same builder, for chaining.

handle.snapshot()

snapshot(name: string): Promise<Snapshot>
const h = await Sandbox.get("baseline");
await h.stop();
const snap = await h.snapshot("after-pip-install");
Snapshot this sandbox under a bare name in the default snapshots directory (~/.microsandbox/snapshots/<name>/). Called on a SandboxHandle. The sandbox must be stopped or crashed; running sandboxes are rejected with a SnapshotSandboxRunning error. For an explicit filesystem destination, see snapshotTo().

Parameters

namestring
Bare name; becomes the artifact directory under the default snapshots dir.

Returns

The created snapshot artifact.

handle.snapshotTo()

snapshotTo(path: string): Promise<Snapshot>
const snap = await h.snapshotTo("/data/snapshots/baseline-v2");
Snapshot this sandbox to an explicit filesystem path. Called on a SandboxHandle. The sandbox must be stopped or crashed.

Parameters

pathstring
Destination artifact directory path.

Returns

The created snapshot artifact.

Snapshot static methods

Snapshot.builder()

static builder(sourceSandbox: string): SnapshotBuilder
const snap = await Snapshot.builder("baseline")
  .name("after-pip-install")
  .label("stage", "post-deps")
  .recordIntegrity()
  .create();
Begin building a new snapshot of sourceSandbox (which must be stopped). The fluent builder is what powers the CLI internally. The bare-name and explicit-path destinations are mutually exclusive: call exactly one of .name() or .path(). See SnapshotBuilder for all setters.

Parameters

sourceSandboxstring
Name of the stopped sandbox to capture.

Returns

Builder for configuring the snapshot.

Snapshot.open()

static open(pathOrName: string): Promise<Snapshot>
const snap = await Snapshot.open("after-pip-install");
console.log(snap.digest);
Open an existing snapshot artifact. Bare names resolve under the default snapshots directory; anything else is treated as a path. Cheap metadata validation only; it does not read the upper file. Use verify() for content checks.

Parameters

pathOrNamestring
Bare name (resolved under the default snapshots dir) or filesystem path.

Returns

The opened snapshot.

Snapshot.get()

static get(nameOrDigest: string): Promise<SnapshotHandle>
const h = await Snapshot.get("after-pip-install");
console.log(h.digest, h.createdAt);
Look up an indexed snapshot by digest, name, or path. Returns a lightweight SnapshotHandle backed by the local index row.

Parameters

nameOrDigeststring
Name, digest (sha256:…), or path of an indexed snapshot.

Returns

Index-backed handle.

Snapshot.list()

static list(): Promise<SnapshotHandle[]>
for (const h of await Snapshot.list()) {
  console.log(h.name ?? h.digest, h.sizeBytes);
}
List indexed snapshots from the local DB cache.

Returns

All indexed snapshot handles.

Snapshot.listDir()

static listDir(dir: string): Promise<Snapshot[]>
const found = await Snapshot.listDir("/mnt/external/snapshots");
console.log(`${found.length} artifacts`);
Walk a directory and parse each subdirectory’s manifest. Does not touch the index, useful for inspecting external snapshot collections that were never imported. Skips entries that don’t look like snapshot artifacts.

Parameters

dirstring
Directory to scan for artifact subdirectories.

Returns

Parsed snapshots found in the directory.

Snapshot.remove()

static remove(pathOrName: string, opts?: { force?: boolean }): Promise<void>
await Snapshot.remove("after-pip-install", { force: true });
Remove a snapshot by path, name, or digest. Refuses if the snapshot has indexed children unless force is set.

Parameters

pathOrNamestring
Path, name, or digest of the snapshot to remove.
opts.forceboolean
Remove even if the snapshot has indexed children. Defaults to false.

Snapshot.reindex()

static reindex(dir?: string): Promise<number>
const count = await Snapshot.reindex();
console.log(`reindexed ${count} snapshots`);
Walk the snapshots directory (default: the configured snapshots dir) and rebuild the local index. Returns the number of artifacts indexed.

Parameters

dirstring
Directory to scan. Defaults to the configured snapshots dir.

Returns

Promise<number>
Count of artifacts indexed.

Snapshot.export()

static export(nameOrPath: string, out: string, opts?: ExportOpts): Promise<void>
await Snapshot.export("after-pip-install", "./baseline.tar.zst", {
  withImage: true,
});
Bundle a snapshot into a .tar.zst archive. When the snapshot has no integrity hash yet, one is computed and embedded in the bundled manifest so the receiver can verify. See ExportOpts for bundling options.

Parameters

nameOrPathstring
Name or path of the snapshot to bundle.
outstring
Output archive path.
Bundling options. All fields default to false.

Snapshot.import()

static import(archive: string, dest?: string): Promise<SnapshotHandle>
const h = await Snapshot.import("./baseline.tar.zst");
console.log("imported", h.digest);
Unpack a snapshot archive (.tar.zst or .tar) into the snapshots directory, verifying recorded integrity on the way in. Compression is detected from magic bytes.

Parameters

archivestring
Path to the archive to unpack.
deststring
Destination directory. Defaults to the snapshots directory.

Returns

Handle to the imported snapshot.

Snapshot instance members

A Snapshot is a snapshot artifact on disk. The artifact is a directory containing manifest.json and the captured upper.ext4. The directory is the source of truth; the local DB index is just a rebuildable cache. Returned by Snapshot.builder().create(), Snapshot.open(), handle.snapshot(), and handle.snapshotTo().

snap.path

get path(): string
Path to the artifact directory.

snap.digest

get digest(): string
Canonical content digest (sha256:hex). The snapshot’s identity.

snap.sizeBytes

get sizeBytes(): bigint
Apparent size of the captured upper layer in bytes (sparse on disk).

snap.imageRef

get imageRef(): string
Image reference the snapshot was taken from.

snap.imageManifestDigest

get imageManifestDigest(): string
OCI manifest digest of the pinned image.

snap.format

get format(): "raw" | "qcow2"
On-disk format of the upper layer.

snap.fstype

get fstype(): string
Filesystem type inside the upper (e.g. "ext4").

snap.parent

get parent(): string | null
Manifest digest of the parent snapshot, or null for a root.

snap.createdAt

get createdAt(): string
RFC 3339 timestamp when the snapshot was created.

snap.labels

get labels(): ReadonlyArray<readonly [string, string]>
User-supplied labels (sorted by key in canonical form), as [key, value] pairs.

snap.sourceSandbox

get sourceSandbox(): string | null
Best-effort source-sandbox name, if recorded. null when the manifest has no source recorded.

snap.verify()

verify(): Promise<SnapshotVerifyReport>
const report = await snap.verify();
if (report.upper.kind === "verified") {
  console.log(`hash matches: ${report.upper.digest}`);
} else {
  console.log("no integrity hash recorded");
}
Recompute the upper layer’s content hash and compare against the manifest. Walks data extents only, so a 4 GiB sparse file with a few MB of data verifies in milliseconds. The report’s upper.kind is "notRecorded" when the manifest has no integrity hash recorded.

Returns

Verification result.

SnapshotBuilder

Fluent builder for a snapshot, returned by Snapshot.builder(name). Every setter mutates in place and returns this, so calls chain. Pick exactly one destination: .name() or .path().

.name()

name(name: string): this
Set a bare name; the artifact lands under the default snapshots directory. Mutually exclusive with .path().

Parameters

namestring
Bare snapshot name.

.path()

path(path: string): this
Set an explicit filesystem path for the artifact. Mutually exclusive with .name().

Parameters

pathstring
Destination artifact directory path.

.label()

label(key: string, value: string): this
Add a key=value label to the snapshot manifest. May be called repeatedly.

Parameters

keystring
Label key.
valuestring
Label value.

.force()

force(): this
Overwrite an existing artifact at the destination instead of failing on conflict.

.recordIntegrity()

recordIntegrity(): this
Compute and record a content-integrity hash of the upper layer at creation time, so the snapshot can be verified later or across a trust boundary.

.create()

create(): Promise<Snapshot>
const snap = await Snapshot.builder("baseline")
  .path("/data/snapshots/baseline-v2")
  .force()
  .recordIntegrity()
  .create();
Capture the configured snapshot and return the resulting artifact.

Returns

The created snapshot artifact.

Types

SnapshotHandle class

Lightweight handle backed by an index row. Values are snapshotted from the index at construction time; call Snapshot.get() again for a fresh reading if needed. Handles from Snapshot.list() are read-only and throw on open() / remove(); fetch a live handle via Snapshot.get() for those lifecycle methods.

Returned by Snapshot.get(), Snapshot.list(), Snapshot.import()

MemberTypeDescription
digeststringManifest digest (sha256:hex), the canonical identity.
namestring | nullConvenience name; null for digest-only entries.
parentDigeststring | nullParent snapshot’s manifest digest, or null for a root.
imageRefstringImage reference the snapshot was taken from.
format"raw" | "qcow2"On-disk format of the upper layer.
sizeBytesbigint | nullApparent size of the upper file at index time.
createdAtDateSnapshot creation time (from manifest).
pathstringLocal artifact directory path.
open()Promise<Snapshot>Open and metadata-validate the underlying artifact.
remove(opts?)Promise<void>Remove the artifact and its index row; refuses on children unless force.

snapshotHandle.open()

open(): Promise<Snapshot>
Open and metadata-validate the underlying artifact. Throws if this handle is read-only (came from Snapshot.list()); fetch a live handle via Snapshot.get() first.

snapshotHandle.remove()

remove(opts?: { force?: boolean }): Promise<void>
Remove the artifact and its index row. Refuses if the snapshot has indexed children unless force is set. Throws if this handle is read-only.
const h = await Snapshot.get("after-pip-install");
const snap = await h.open();          // metadata-validated
await h.remove({ force: false });     // refuse if it has children

ExportOpts interface

Bundle options for Snapshot.export(). All fields default to false.

Used by Snapshot.export()

FieldTypeDescription
withParentsbooleanWalk the parent chain and include each ancestor (no-op in v1).
withImagebooleanInclude the OCI image cache so the archive boots offline.
plainTarbooleanSkip zstd compression and write a plain .tar.

SnapshotVerifyReport union

Result of snap.verify(). The upper discriminant is "notRecorded" when no integrity hash was stored at create time, or "verified" when the recorded hash matched the recomputed one.

Returned by snap.verify()

type SnapshotVerifyReport =
  | {
      readonly digest: string;
      readonly path: string;
      readonly upper: { readonly kind: "notRecorded" };
    }
  | {
      readonly digest: string;
      readonly path: string;
      readonly upper: {
        readonly kind: "verified";
        readonly algorithm: string;
        readonly digest: string;
      };
    };
FieldTypeDescription
digeststringSnapshot’s manifest digest.
pathstringArtifact directory path.
upper.kind"notRecorded" | "verified"Whether an integrity hash was recorded and checked.
upper.algorithmstringHash algorithm ("verified" only).
upper.digeststringRecomputed upper-layer digest ("verified" only).