sandbox/volumes.md
Deno Sandbox provides two storage primitives:
Persistent volumes let you attach regional block storage to a sandbox so data survives process restarts and new connections. They are ideal for package caches, build artifacts, SQLite databases, or any workflow that needs a small amount of durable storage without promoting code to a full Deno Deploy app.
import { Client } from "@deno/sandbox";
const client = new Client();
const volume = await client.volumes.create({
slug: "training-cache",
region: "ord", // ord (Chicago) or ams (Amsterdam)
capacity: "2GB", // accepts bytes or "1GB"/"512MB" style strings
});
console.log(volume);
// {
// id: "8a0f...",
// slug: "training-cache",
// region: "ord",
// capacity: 2147483648,
// used: 0
// }
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
volume = sdk.volumes.create(
slug="training-cache",
region="ord", # ord (Chicago) or ams (Amsterdam)
capacity="2GB" # accepts bytes or "1GB"/"512MB" style strings
)
print(volume)
# {
# "id": "8a0f...",
# "slug": "training-cache",
# "region": "ord",
# "capacity": 2147483648,
# "used": 0
# }
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
volume = await sdk.volumes.create(
slug="training-cache",
region="ord", # ord (Chicago) or ams (Amsterdam)
capacity="2GB" # accepts bytes or "1GB"/"512MB" style strings
)
print(volume)
# {
# "id": "8a0f...",
# "slug": "training-cache",
# "region": "ord",
# "capacity": 2147483648,
# "used": 0
# }
| Field | Required | Details |
|---|---|---|
slug | ✅ | Unique per organization. Slugs become part of the mount metadata, so pick something descriptive. |
region | ✅ | Must match an available sandbox region ("ord" or "ams" today). Only sandboxes in the same region can mount the volume. |
capacity | ✅ | Between 300 MB and 20 GB. Pass a number of bytes or a string with GB/MB/KB (decimal) or GiB/MiB/KiB (binary) units. |
The volumes API returns paginated results and can fetch a single record by slug or UUID.
<deno-tabs group-id="sandbox-sdk"> <deno-tab value="js" label="JavaScript" default>const page = await client.volumes.list({ search: "training" });
for (const vol of page.items) {
console.log(vol.slug, vol.estimatedFlattenedSize, vol.capacity);
}
const vol = await client.volumes.get("training-cache");
page = sdk.volumes.list(search="training")
for vol in page.items:
print(f"{vol['slug']} {vol['estimatedFlattenedSize']} {vol['capacity']}")
vol = sdk.volumes.get("training-cache")
page = await sdk.volumes.list(search="training")
async for vol in page:
print(f"{vol['slug']} {vol['estimatedFlattenedSize']} {vol['capacity']}")
vol = await sdk.volumes.get("training-cache")
The used field reports the most recent estimate the control plane received
from the underlying cluster. It can lag a few minutes behind reality, so always
size volumes with headroom.
Pass a volumes mapping when creating a sandbox. Keys are mount paths and
values are either the volume slug or ID. The sandbox and volume must be in the
same region.
:::note
Sandbox.create() and client.sandboxes.create() are equivalent—use whichever
fits your code style.
:::
<deno-tabs group-id="sandbox-sdk"> <deno-tab value="js" label="JavaScript" default>import { Client, Sandbox } from "@deno/sandbox";
const client = new Client();
const volume = await client.volumes.create({
slug: "dataset",
region: "ord",
capacity: "1GB",
});
// First run writes a file to the volume
{
await using sandbox = await Sandbox.create({
region: "ord",
volumes: {
"/data/dataset": volume.slug,
},
labels: { job: "prepare" },
});
await sandbox.fs.writeTextFile("/data/dataset/hello.txt", "Persist me!\n");
}
// A new sandbox—possibly started hours later—can read the same file
{
await using sandbox = await Sandbox.create({
region: "ord",
volumes: {
"/data/dataset": volume.id, // IDs work too
},
});
const contents = await sandbox.fs.readTextFile("/data/dataset/hello.txt");
console.log(contents); // "Persist me!"
}
from deno_sandbox import DenoDeploy
sdk = DenoDeploy()
volume = sdk.volumes.create(
slug="dataset",
region="ord",
capacity="1GB"
)
# First run writes a file to the volume
with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["slug"],
},
labels={"job": "prepare"}
) as sandbox:
sandbox.fs.write_text_file("/data/dataset/hello.txt", "Persist me!\n")
# A new sandbox—possibly started hours later—can read the same file
with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["id"], # IDs work too
}
) as sandbox:
contents = sandbox.fs.read_text_file("/data/dataset/hello.txt")
print(contents) # "Persist me!"
from deno_sandbox import AsyncDenoDeploy
sdk = AsyncDenoDeploy()
volume = await sdk.volumes.create(
slug="dataset",
region="ord",
capacity="1GB"
)
# First run writes a file to the volume
async with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["slug"],
},
labels={"job": "prepare"}
) as sandbox:
await sandbox.fs.write_text_file("/data/dataset/hello.txt", "Persist me!\n")
# A new sandbox—possibly started hours later—can read the same file
async with sdk.sandbox.create(
region="ord",
volumes={
"/data/dataset": volume["id"], # IDs work too
}
) as sandbox:
contents = await sandbox.fs.read_text_file("/data/dataset/hello.txt")
print(contents) # "Persist me!"
Mounts behave like regular directories. You can create subfolders, write binary files, or execute programs directly from the volume.
await client.volumes.delete("training-cache");
sdk.volumes.delete("training-cache")
await sdk.volumes.delete("training-cache")
Deletion is a two-step process:
During the grace period you cannot mount or read the volume.
Snapshots are read-only images created from volumes. When a sandbox boots with a
snapshot as its root, the entire filesystem is replaced with the snapshot
contents. Run apt-get install or npm install once, snapshot the result, and
every future sandbox starts instantly with everything already installed.
The workflow is:
root (writable)Sandboxes booted from the snapshot start instantly with everything installed.
A volume is bootable when created with the from option. Currently
builtin:debian-13 is the only available base image.
import { Client } from "@deno/sandbox";
const client = new Client();
// 1. Create a bootable volume
const volume = await client.volumes.create({
region: "ord",
slug: "my-toolchain",
capacity: "10GiB",
from: "builtin:debian-13",
});
// 2. Boot a sandbox with the volume as root (writable)
await using sandbox = await client.sandboxes.create({
region: "ord",
root: volume.slug,
});
// 3. Install software
await sandbox.sh`apt-get update && apt-get install -y nodejs npm`;
await sandbox.sh`npm install -g typescript`;
// 4. Snapshot the volume
const snapshot = await client.volumes.snapshot(volume.id, {
slug: "my-toolchain-snapshot",
});
# Create snapshot from a volume
deno sandbox snapshots create my-toolchain my-toolchain-snapshot
Once you have a snapshot, use it as the root when creating new sandboxes. The
sandbox must be created in the same region as the snapshot:
await using sandbox = await client.sandboxes.create({
region: "ord",
root: "my-toolchain-snapshot", // snapshot slug or ID
});
// TypeScript and Node.js are already installed
await sandbox.sh`tsc --version`;
await sandbox.sh`node --version`;
The sandbox boots with the snapshot's filesystem as its root. Any writes during the session are ephemeral—they don't modify the snapshot.
const page = await client.snapshots.list();
for (const snap of page.items) {
console.log(snap.slug, snap.region, snap.bootable);
}
$ deno sandbox snapshots list
ID SLUG REGION ALLOCATED BOOTABLE
snp_ord_spmbe47dysccpy277ma6 my-toolchain-snapshot ord 217.05 MiB TRUE
Create a new writable volume from a snapshot:
<deno-tabs group-id="sandbox-sdk"> <deno-tab value="js" label="JavaScript" default>const volume = await client.volumes.create({
region: "ord",
slug: "my-toolchain-fork",
capacity: "10GiB",
from: "my-toolchain-snapshot",
});
The new volume contains the snapshot's contents and is fully writable. Use this to modify a snapshot's contents, then snapshot again.
await client.snapshots.delete("my-toolchain-snapshot");
deno sandbox snapshots delete my-toolchain-snapshot
| Feature | Volumes | Snapshots |
|---|---|---|
| Access | Read-write | Read-only |
| Mount point | Any path, or root if bootable | Root filesystem only |
| Use case | Caches, databases, install software | Pre-installed software, toolchains |
| Concurrent use | One sandbox at a time | Many sandboxes simultaneously |
| Region | Must match sandbox region | Must match sandbox region |