docs/sandboxes/volumes.mdx
Volumes give a sandbox direct filesystem access to host-side directories. They're useful for persisting data across restarts, sharing data between sandboxes, or mounting host directories into the guest. They're also significantly faster than the filesystem API (which transfers files individually), so for anything beyond ad-hoc reads and writes, volumes are the way to go.
microsandbox supports three types of mounts: bind mounts, named volumes, and tmpfs.
Mount a directory from the host directly into the sandbox. Changes inside the sandbox are reflected on the host, and vice versa.
<CodeGroup> ```rust Rust let sb = Sandbox::builder("dev") .image("python") .volume("/app/src", |v| v.bind("./src").readonly()) .volume("/app/data", |v| v.bind("./data")) .create() .await?; ```import { Sandbox } from "microsandbox";
await using sb = await Sandbox.builder("dev")
.image("python")
.volume("/app/src", (m) => m.bind("./src").readonly())
.volume("/app/data", (m) => m.bind("./data"))
.create();
from microsandbox import Sandbox, Volume
sb = await Sandbox.create(
"dev",
image="python",
volumes={
"/app/src": Volume.bind("./src", readonly=True),
"/app/data": Volume.bind("./data"),
},
)
msb create python --name dev \
-v ./src:/app/src:ro \
-v ./data:/app/data
Named volumes are managed by microsandbox and stored at ~/.microsandbox/volumes/<name>/. They persist independently of any sandbox, so you can create a volume, populate it, and mount it into different sandboxes over time.
import { Volume } from "microsandbox";
const cache = await Volume.builder("pip-cache").quota(1024).create();
cache = await Volume.create("pip-cache", quota_mib=1024)
msb volume create pip-cache --size 1024
await using sb = await Sandbox.builder("worker")
.image("python")
.volume("/root/.cache/pip", (m) => m.named(cache.name))
.create();
sb = await Sandbox.create(
"worker",
image="python",
volumes={
"/root/.cache/pip": Volume.named(cache.name),
},
)
msb create python --name worker \
-v pip-cache:/root/.cache/pip
Named volumes are the simplest way to share data between sandboxes. Mount the same volume into multiple sandboxes: one writes, another reads.
<CodeGroup> ```rust Rust // Writer let writer = Sandbox::builder("writer") .image("alpine") .volume("/data", |v| v.named("shared-data")) .create() .await?; writer.shell("echo 'hello' > /data/message.txt").await?;// Reader (read-only) let reader = Sandbox::builder("reader") .image("alpine") .volume("/data", |v| v.named("shared-data").readonly()) .create() .await?; let output = reader.exec("cat", ["/data/message.txt"]).await?; // => "hello"
```typescript TypeScript
// Writer
await using writer = await Sandbox.builder("writer")
.image("alpine")
.volume("/data", (m) => m.named("shared-data"))
.create();
await writer.shell("echo 'hello' > /data/message.txt");
// Reader (read-only)
await using reader = await Sandbox.builder("reader")
.image("alpine")
.volume("/data", (m) => m.named("shared-data").readonly())
.create();
const output = await reader.exec("cat", ["/data/message.txt"]);
// => "hello"
# Writer
writer = await Sandbox.create(
"writer",
image="alpine",
volumes={"/data": Volume.named("shared-data")},
)
await writer.shell("echo 'hello' > /data/message.txt")
# Reader (read-only)
reader = await Sandbox.create(
"reader",
image="alpine",
volumes={"/data": Volume.named("shared-data", readonly=True)},
)
output = await reader.exec("cat", ["/data/message.txt"])
# => "hello"
Named volumes are accessible from the host even without a running sandbox, which is handy for pre-populating data before any sandbox mounts it.
<CodeGroup> ```rust Rust let vol = Volume::get("pip-cache").await?; vol.fs().write("/requirements.txt", "requests==2.28.0").await?; ```const vol = await Volume.get("pip-cache");
await vol.fs().write("requirements.txt", "requests==2.28.0");
vol = await Volume.get("pip-cache")
await vol.fs.write("/requirements.txt", b"requests==2.28.0")
const volumes = await Volume.list();
await Volume.remove("old-cache");
volumes = await Volume.list()
await Volume.remove("old-cache")
msb volume ls
msb volume rm old-cache
An in-memory filesystem that disappears when the sandbox stops. Useful for scratch space, build artifacts, or anything that doesn't need to outlive the sandbox.
<CodeGroup> ```rust Rust let sb = Sandbox::builder("worker") .image("alpine") .volume("/tmp/scratch", |v| v.tmpfs().size(100)) .create() .await?; ```import { Sandbox } from "microsandbox";
await using sb = await Sandbox.builder("worker")
.image("alpine")
.volume("/tmp/scratch", (m) => m.tmpfs().size(100))
.create();
sb = await Sandbox.create(
"worker",
image="alpine",
volumes={
"/tmp/scratch": Volume.tmpfs(size_mib=100),
},
)
msb create alpine --name worker \
--tmpfs /tmp/scratch:100