Skip to main content
Capture a stopped sandbox’s writable upper layer into a self-describing, content-addressed artifact on disk, then list, verify, export, import, or boot a fresh sandbox from it. See Snapshots for concepts and walkthroughs; this page is the Rust SDK reference.
Snapshots are local-only and disk-only today: they capture a sandbox that is stopped or crashed, and every operation runs against the default local backend. Cloud snapshots and qcow2 backing chains are deferred.

Typical flow

use microsandbox::{Sandbox, Snapshot};

// 1. stop the sandbox you want to capture
let sb = Sandbox::get("api").await?;
sb.stop().await?;

// 2. capture its writable upper layer
let snap = Snapshot::builder("api")
    .name("after-pip-install")     // bare name in the default dir
    .record_integrity()            // hash the upper layer
    .create()
    .await?;
println!("{} ({} bytes)", snap.digest(), snap.size_bytes());

// 3. boot a fresh sandbox from it
let restored = Sandbox::builder("api-restored")
    .from_snapshot("after-pip-install")
    .create()
    .await?;

Static methods

Snapshot::builder()

fn builder(source_sandbox: impl Into<String>) -> SnapshotBuilder
let snap = Snapshot::builder("api")
    .name("baseline")
    .create()
    .await?;
Start configuring a new snapshot of source_sandbox. The builder lets you set the destination, labels, and whether to record content integrity before capturing. See SnapshotBuilder for all options.

Parameters

source_sandboximpl Into<String>
Name of the source sandbox. Must be stopped or crashed, and rooted on an OCI image.

Returns

Builder for configuring the snapshot.

Snapshot::create()

async fn create(config: SnapshotConfig) -> MicrosandboxResult<Snapshot>
let snap = Snapshot::create(
    Snapshot::builder("api").name("baseline").build()?
).await?;
Create a snapshot artifact from a stopped sandbox. Writes manifest.json and the captured upper.ext4 into the destination directory atomically (the manifest is renamed into place last), then best-effort upserts a row into the local index. Index failures are logged but do not fail the call; the artifact is the source of truth. Most callers use the builder’s create() instead of constructing a SnapshotConfig by hand.

Parameters

Source sandbox, destination, labels, and integrity flag.

Returns

The created artifact handle.

Snapshot::open()

async fn open(path_or_name: impl AsRef<str>) -> MicrosandboxResult<Snapshot>
let snap = Snapshot::open("baseline").await?;
println!("{}", snap.manifest().image.reference);
Open an existing artifact by path or bare name. Bare names (no path separator, not starting with . or ~) resolve under the default snapshots directory; anything else is treated as a path. This is a fast metadata operation: it verifies the manifest structure, recomputes the manifest digest, and checks that the upper file exists with the recorded size. It does not read the full upper contents; use verify() for that.

Parameters

path_or_nameimpl AsRef<str>
Bare snapshot name or filesystem path to an artifact directory.

Returns

The opened artifact handle.

Snapshot::get()

async fn get(name_or_digest: &str) -> MicrosandboxResult<SnapshotHandle>
let h = Snapshot::get("after-pip-install").await?;
println!("{} from {}", h.digest(), h.image_ref());
Look up a lightweight SnapshotHandle in the local index by name, digest (sha256:/sha512: prefix), or path.

Parameters

name_or_digest&str
Snapshot name, manifest digest, or artifact path.

Returns

Handle backed by the matching index row.

Snapshot::list()

async fn list() -> MicrosandboxResult<Vec<SnapshotHandle>>
for h in Snapshot::list().await? {
    println!("{:?} - {}", h.name(), h.digest());
}
List indexed snapshots from the local DB cache, newest first. External-path artifacts booted by full path aren’t in the index and won’t appear here; use list_dir to enumerate artifacts on disk directly.

Returns

Indexed snapshot handles, ordered by creation time descending.

Snapshot::list_dir()

async fn list_dir(dir: impl AsRef<Path>) -> MicrosandboxResult<Vec<Snapshot>>
let snaps = Snapshot::list_dir("/data/snapshots").await?;
println!("{} artifacts", snaps.len());
Walk a directory and parse each subdirectory’s manifest. Does not touch the index. Skips entries that don’t look like snapshot artifacts (no manifest.json) and malformed artifacts.

Parameters

dirimpl AsRef<Path>
Directory to scan for artifacts.

Returns

One handle per valid artifact found.

Snapshot::remove()

async fn remove(path_or_name: &str, force: bool) -> MicrosandboxResult<()>
Snapshot::remove("after-pip-install", false).await?;
Remove a snapshot artifact (by digest, name, or path) and its index row. Refuses if the snapshot has indexed children unless force is set. The artifact directory is deleted on success and the parent’s child count is decremented.

Parameters

path_or_name&str
Snapshot digest, name, or artifact path.
forcebool
When true, remove even if the snapshot has indexed children.

Snapshot::reindex()

async fn reindex(dir: impl AsRef<Path>) -> MicrosandboxResult<usize>
let n = Snapshot::reindex("/data/snapshots").await?;
println!("indexed {n} snapshots");
Rebuild the local index from the artifacts in dir. Upserts an index row for every artifact found, then recomputes parent-edge child counts in one pass so the cache stays honest about the current set of artifacts.

Parameters

dirimpl AsRef<Path>
Directory of artifacts to index.

Returns

usize
Number of artifacts indexed.

Snapshot::export()

async fn export(name_or_path: &str, out: &Path, opts: ExportOpts) -> MicrosandboxResult<()>
use microsandbox::snapshot::ExportOpts;
use std::path::Path;

Snapshot::export(
    "baseline",
    Path::new("/tmp/baseline.tar.zst"),
    ExportOpts { with_parents: true, with_image: true, ..Default::default() },
).await?;
Bundle a snapshot into a .tar.zst archive (or plain .tar) at out. The head snapshot is verified before bundling. The recorded manifest is archived as-is, so create the snapshot with record_integrity() when the archive will cross a trust boundary. See ExportOpts to also include ancestors and the OCI image cache.

Parameters

name_or_path&str
Snapshot name or artifact path to export.
out&Path
Output archive path. Parent directories are created if missing.
Bundling options. ExportOpts::default() writes the head snapshot only, zstd-compressed.

Snapshot::import()

async fn import(archive_path: &Path, dest: Option<&Path>) -> MicrosandboxResult<SnapshotHandle>
use std::path::Path;

let h = Snapshot::import(Path::new("/tmp/baseline.tar.zst"), None).await?;
println!("imported {}", h.digest());
Unpack a snapshot archive (.tar.zst or .tar, detected from magic bytes) into the snapshots directory (or dest), routing any bundled image-cache entries into the global cache and registering everything found in the index. Recorded integrity is verified as artifacts land. Returns a handle for the head snapshot.

Parameters

archive_path&Path
Archive to unpack.
destOption<&Path>
Destination directory. None uses the default snapshots directory.

Returns

Handle for the head (last-listed) snapshot.

Instance methods

Methods on an opened Snapshot artifact.

snap.digest()

fn digest(&self) -> &str
Canonical content digest of this snapshot’s manifest (sha256:hex). This is the snapshot’s identity.

Returns

&str
Manifest digest in sha256:hex form.

snap.path()

fn path(&self) -> &Path
Path to the artifact directory holding the canonical manifest.json and the captured upper file.

Returns

&Path
Artifact directory path.

snap.manifest()

fn manifest(&self) -> &Manifest
let snap = Snapshot::open("baseline").await?;
let m = snap.manifest();
println!("{} @ {}", m.image.reference, m.image.manifest_digest);
The parsed Manifest: schema, format, fstype, image reference, parent, creation time, labels, and upper-layer metadata.

Returns

Parsed snapshot manifest.

snap.size_bytes()

fn size_bytes(&self) -> u64
Apparent size of the captured upper layer in bytes (the ext4 virtual size; sparse on disk).

Returns

u64
Upper-layer apparent size in bytes.

snap.verify()

async fn verify(&self) -> MicrosandboxResult<SnapshotVerifyReport>
use microsandbox::snapshot::UpperVerifyStatus;

let snap = Snapshot::open("baseline").await?;
match snap.verify().await?.upper {
    UpperVerifyStatus::Verified { algorithm, .. } => println!("ok via {algorithm}"),
    UpperVerifyStatus::NotRecorded => println!("no integrity hash recorded"),
}
Recompute the upper layer’s content hash and compare it against the manifest. Walks data extents only, so a multi-GiB sparse file with a little data verifies in milliseconds. Returns NotRecorded when the manifest has no integrity descriptor; errors with SnapshotIntegrity on mismatch.

Returns

Digest, path, and upper-layer verification status.

SnapshotHandle methods

Accessors and lifecycle on a SnapshotHandle (an index row). Returned by Snapshot::get(), Snapshot::list(), and Snapshot::import().

h.digest()

fn digest(&self) -> &str
Manifest digest (sha256:hex), the canonical identity.

h.name()

fn name(&self) -> Option<&str>
Name alias, or None for digest-only entries.

h.parent_digest()

fn parent_digest(&self) -> Option<&str>
The parent snapshot’s digest, or None for a root. Always None today; populated once chained snapshots land.

h.image_ref()

fn image_ref(&self) -> &str
Image reference the snapshot was taken from.

h.format()

fn format(&self) -> SnapshotFormat
On-disk format of the upper layer.

Returns

Upper-layer format (Raw today).

h.size_bytes()

fn size_bytes(&self) -> Option<u64>
Apparent size of the upper file at index time, if recorded.

h.created_at()

fn created_at(&self) -> chrono::NaiveDateTime
Snapshot creation time, parsed from the manifest.

h.path()

fn path(&self) -> &Path
Local artifact directory path.

h.open()

async fn open(&self) -> MicrosandboxResult<Snapshot>
let h = Snapshot::get("baseline").await?;
let snap = h.open().await?;
snap.verify().await?;
Open the underlying artifact metadata, upgrading this lightweight handle to a full Snapshot. Equivalent to Snapshot::open(self.path()).

Returns

The opened artifact.

h.remove()

async fn remove(&self, force: bool) -> MicrosandboxResult<()>
let h = Snapshot::get("baseline").await?;
h.remove(false).await?;
Remove this snapshot. Delegates to Snapshot::remove(self.digest(), force).

Parameters

forcebool
When true, remove even if the snapshot has indexed children.

Sandbox entry points

Snapshot-related methods that live on the sandbox builder and handle. See Sandbox for the full sandbox API.

.from_snapshot()

fn from_snapshot(self, path_or_name: impl Into<String>) -> Self
let sb = Sandbox::builder("api-restored")
    .from_snapshot("after-pip-install")
    .create()
    .await?;
SandboxBuilder setter. Boot a fresh sandbox from a snapshot artifact. The snapshot already pins the image reference and digest, so this is mutually exclusive with image() and image_with(). The artifact is opened and its integrity verified at create() time, not here.

Parameters

path_or_nameimpl Into<String>
Bare name resolved under the default snapshots directory, or a path to an artifact directory.

h.snapshot()

async fn snapshot(&self, name: &str) -> MicrosandboxResult<Snapshot>
let h = Sandbox::get("api").await?;
h.stop().await?;
let snap = h.snapshot("baseline").await?;
SandboxHandle method. Snapshot this sandbox under a bare name in the default snapshots directory (~/.microsandbox/snapshots/<name>/). The sandbox must be stopped or crashed; running sandboxes are rejected with SnapshotSandboxRunning. Local handles only. For an explicit destination see snapshot_to().

Parameters

name&str
Bare snapshot name.

Returns

The created artifact handle.

h.snapshot_to()

async fn snapshot_to(&self, path: impl AsRef<Path>) -> MicrosandboxResult<Snapshot>
let h = Sandbox::get("api").await?;
h.stop().await?;
let snap = h.snapshot_to("/data/snapshots/baseline").await?;
SandboxHandle method. Snapshot this sandbox to an explicit filesystem path. The sandbox must be stopped or crashed. Local handles only. For the common case of writing under the default snapshots directory see snapshot().

Parameters

pathimpl AsRef<Path>
Destination artifact directory.

Returns

The created artifact handle.

SnapshotBuilder

Builder for a SnapshotConfig. Obtained via Snapshot::builder(source_sandbox). A destination is required (name or path); the other setters are optional. Every setter returns Self, so calls chain.
let snap = Snapshot::builder("api")
    .name("after-pip-install")     // bare name in default dir
    .label("stage", "post-deps")
    .force()                       // overwrite if it exists
    .record_integrity()            // hash the upper layer
    .create()
    .await?;

.destination()

fn destination(self, dest: SnapshotDestination) -> Self
Set the artifact destination explicitly. The name and path setters are convenience wrappers over this.

Parameters

Name- or path-based destination.

.name()

fn name(self, name: impl Into<String>) -> Self
Convenience: use a bare name resolved under the default snapshots directory. Sets the destination to SnapshotDestination::Name.

Parameters

nameimpl Into<String>
Bare snapshot name. Must not be empty, contain /, or start with ..

.path()

fn path(self, path: impl Into<PathBuf>) -> Self
Convenience: write the artifact to an explicit path. Sets the destination to SnapshotDestination::Path.

Parameters

pathimpl Into<PathBuf>
Destination artifact directory.

.label()

fn label(self, key: impl Into<String>, value: impl Into<String>) -> Self
Add a user label. Can be called multiple times. Labels are sorted by key in the manifest’s canonical form.

Parameters

keyimpl Into<String>
Label key.
valueimpl Into<String>
Label value.

.force()

fn force(self) -> Self
Overwrite an existing artifact at the destination. Without this, creation fails with SnapshotAlreadyExists if the destination directory exists.

.record_integrity()

fn record_integrity(self) -> Self
Compute and record an upper-layer content-integrity hash during creation. Recorded integrity is what verify() checks and what import/export rely on when crossing a trust boundary.

.build()

fn build(self) -> MicrosandboxResult<SnapshotConfig>
Materialize the SnapshotConfig without creating the snapshot. Errors with InvalidConfig if no destination was set. For capturing, use create instead; it calls build internally.

Returns

Validated snapshot configuration.

.create()

async fn create(self) -> MicrosandboxResult<Snapshot>
Build and execute the snapshot in one step. Equivalent to Snapshot::create(self.build()?).

Returns

The created artifact handle.

Types

SnapshotHandle

Returned by Snapshot::get() · Snapshot::list() · Snapshot::import()

A lightweight handle backed by a local index row. Use open() to read the artifact metadata, and Snapshot::verify() for explicit content verification. All accessors are listed under SnapshotHandle methods.
MethodTypeDescription
digest()&strManifest digest (sha256:hex)
name()Option<&str>Name alias; None for digest-only entries
parent_digest()Option<&str>Parent snapshot digest, or None for a root
image_ref()&strSource image reference
format()SnapshotFormatOn-disk upper format
size_bytes()Option<u64>Upper file size at index time
created_at()chrono::NaiveDateTimeCreation time from the manifest
path()&PathLocal artifact directory
open()Result<Snapshot>Open the underlying artifact
remove(force)Result<()>Remove this snapshot

SnapshotConfig

Used by Snapshot::create() · returned by build()

Inputs to create a snapshot. A type alias for SnapshotSpec. Usually built via SnapshotBuilder rather than constructed directly.
FieldTypeDescription
source_sandboxStringName of the source sandbox; must be stopped
destinationSnapshotDestinationWhere to write the artifact
labelsVec<(String, String)>User-supplied labels
forceboolOverwrite an existing artifact at the destination
record_integrityboolCompute and record upper-layer integrity at creation

SnapshotDestination

Used by destination() · SnapshotConfig.destination

Where to place a new snapshot artifact. The builder’s name() and path(), and the handle’s snapshot() / snapshot_to(), construct this enum internally so callers rarely import it.
VariantFieldsDescription
NameStringBare name resolved under the default snapshots directory
PathPathBufExplicit absolute or relative path to the artifact directory

SnapshotFormat

Used by format() · Manifest.format

On-disk format of the captured upper layer. Today only Raw is produced; the variant exists so qcow2 chains drop in later without a schema migration.
ValueDescription
RawRaw ext4 image, sparse on disk
Qcow2qcow2 with optional backing chain (future)

ExportOpts

Used by Snapshot::export()

Options for Snapshot::export(). Implements Default; ExportOpts::default() writes the head snapshot only, zstd-compressed.
FieldTypeDescription
with_parentsboolWalk the parent chain and include each ancestor in the archive
with_imageboolBundle the OCI image artifacts (EROFS layers, fsmeta, VMDK descriptor) from the global cache so the archive boots offline
plain_tarboolSkip zstd compression and write a plain .tar. Default: zstd

SnapshotVerifyReport

Returned by verify()

Result of explicit snapshot verification.
FieldTypeDescription
digestStringSnapshot manifest digest
pathPathBufArtifact directory
upperUpperVerifyStatusUpper-layer content verification result

UpperVerifyStatus

Used by SnapshotVerifyReport.upper

Upper-layer content verification result.
VariantFieldsDescription
NotRecorded-No content integrity descriptor was recorded in the manifest
Verified- algorithm: String
- digest: String
Recorded integrity matched the computed digest

Manifest

Returned by manifest()

The snapshot artifact manifest, the source of truth for an artifact. Re-exported as microsandbox::snapshot::Manifest. Its SHA-256 digest over the canonical byte form is the snapshot’s identity. Field order is load-bearing (it determines the canonical byte layout) and must not be reordered.
FieldTypeDescription
schemau32Manifest schema version; readers reject unknown values
formatSnapshotFormatOn-disk format of the upper layer
fstypeStringFilesystem type inside the upper (e.g. ext4)
imageImageRefImage the snapshot was taken from
parentOption<String>Parent snapshot digest, or None for a root
created_atStringRFC 3339 creation timestamp
labelsBTreeMap<String, String>User-supplied labels, sorted by key in canonical form
upperUpperLayerThe captured upper layer
source_sandboxOption<String>Best-effort name of the source sandbox (informational)

ImageRef

Used by Manifest.image

Reference to the OCI image the snapshot was taken from. Re-exported as microsandbox::snapshot::ImageRef.
FieldTypeDescription
referenceStringHuman-readable image reference (e.g. docker.io/library/python:3.12)
manifest_digestStringDigest of the OCI manifest, in sha256:hex form

UpperLayer

Used by Manifest.upper

Captured upper-layer file metadata. Re-exported as microsandbox::snapshot::UpperLayer.
FieldTypeDescription
fileStringFilename inside the artifact directory (e.g. upper.ext4)
size_bytesu64Apparent size in bytes (ext4 virtual size; sparse on disk)
integrityOption<UpperIntegrity>Optional content integrity descriptor; None on local hot paths

UpperIntegrity

Used by UpperLayer.integrity

Content integrity descriptor for the captured upper layer.
FieldTypeDescription
algorithmStringDigest algorithm name (e.g. msb-sparse-sha256-v1)
digestStringAlgorithm output, in sha256:hex form for current algorithms