docs/images/overview.mdx
microsandbox uses standard OCI container images as root filesystems. Docker Hub, GHCR, ECR, GCR, any OCI-compatible registry works. Existing images run as-is.
When you specify an image like python, microsandbox pulls the manifest, downloads the layers in parallel, and stacks them as a copy-on-write filesystem. Changes inside the sandbox don't modify the base image. Two sandboxes using the same image share the same cached layers on disk.
By default, microsandbox pulls an image only if it isn't already cached. You can change this behavior.
| Policy | Behavior |
|---|---|
"if-missing" | Pull only if not cached (default) |
"always" | Always check the registry for updates |
"never" | Use local cache only, fail if missing |
import { Sandbox } from "microsandbox";
await using sb = await Sandbox.builder("worker")
.image("python")
.pullPolicy("always")
.create();
from microsandbox import PullPolicy, Sandbox
sb = await Sandbox.create("worker", image="python", pull_policy=PullPolicy.ALWAYS)
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("python"),
m.WithPullPolicy(m.PullPolicyAlways),
)
Authenticate to private registries by passing credentials.
<CodeGroup> ```rust Rust let sb = Sandbox::builder("worker") .image("registry.corp.io/team/app:latest") .registry(|r| r.auth(RegistryAuth::Basic { username: "deploy".into(), password: std::env::var("REGISTRY_PASSWORD")?, })) .pull_policy(PullPolicy::Always) .create() .await?; ```await using sb = await Sandbox.builder("worker")
.image("registry.corp.io/team/app:latest")
.registry((r) => r.auth({
kind: "basic",
username: "deploy",
password: process.env.REGISTRY_TOKEN!,
}))
.pullPolicy("always")
.create();
import os
from microsandbox import PullPolicy, RegistryAuth, Sandbox
sb = await Sandbox.create(
"worker",
image="registry.corp.io/team/app:latest",
registry_auth=RegistryAuth.basic("deploy", os.environ["REGISTRY_PASSWORD"]),
pull_policy=PullPolicy.ALWAYS,
)
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("registry.corp.io/team/app:latest"),
m.WithRegistryAuth(m.RegistryAuth{
Username: "deploy",
Password: os.Getenv("REGISTRY_PASSWORD"),
}),
m.WithPullPolicy(m.PullPolicyAlways),
)
By default, microsandbox connects to registries over HTTPS using system CA roots. You can customize this per-registry in ~/.microsandbox/config.json.
Local registries often run without TLS. Mark them as insecure to connect over plain HTTP:
{
"registries": {
"hosts": {
"localhost:5050": {
"insecure": true
}
}
}
}
For registries using self-signed or internal CA certificates, point ca_certs to a PEM file. This applies globally to all registry connections:
{
"registries": {
"ca_certs": "/path/to/ca-bundle.pem"
}
}
The certificates are added to the default system roots — public registries continue to work normally.
{
"registries": {
"ca_certs": "/path/to/corporate-ca.pem",
"hosts": {
"localhost:5050": {
"insecure": true,
"auth": { "username": "deploy", "password_env": "REGISTRY_TOKEN" }
},
"ghcr.io": {
"auth": { "username": "user", "store": "keyring" }
}
}
}
}
These settings can also be set per-sandbox via the SDK, overriding global config:
<CodeGroup> ```rust Rust let sb = Sandbox::builder("worker") .image("localhost:5050/my-app:latest") .registry(|r| r.insecure()) .create() .await?; ```await using sb = await Sandbox.builder("worker")
.image("localhost:5050/my-app:latest")
.registry((r) => r.insecure())
.create();
// Per-registry TLS configuration is read from ~/.microsandbox/config.json.
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("localhost:5050/my-app:latest"),
)
Images are cached in the global microsandbox home directory:
| Path | Description |
|---|---|
~/.microsandbox/cache/layers/ | Materialized EROFS image layers |
~/.microsandbox/cache/fsmeta/ | Merged metadata images for cached manifests |
~/.microsandbox/cache/vmdk/ | VMDK descriptors used to boot cached images |
~/.microsandbox/db/ | Database tracking image metadata and digests |
Layers are content-addressable and deduplicated. If python and python share a base layer, it's stored once.
msb load accepts Docker image archives and OCI Image Layout archives. msb save exports from the materialized EROFS cache as a Docker archive by default, or as an OCI Image Layout archive with --format oci. The expanded forms are msb image load and msb image save. The exported image should run the same way after msb load, but it is a regenerated archive: manifest digest and layer digests can differ from the original registry image.