On this page
Volumes & Snapshots
Deno Sandbox provides two storage primitives:
- Volumes – read-write block storage. Use for caches, databases, and artifacts that persist across sessions.
- Snapshots – read-only images created from volumes. Use for pre-installing software so sandboxes boot instantly with everything ready. You can also create new volumes from snapshots.
Volumes Jump to heading
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.
Provision storage Jump to heading
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. |
Inspect and search volumes Jump to heading
The volumes API returns paginated results and can fetch a single record by slug or UUID.
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.
Mount volumes inside a sandbox Jump to heading
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.
Sandbox.create() and client.sandboxes.create() are equivalent—use whichever
fits your code style.
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.
Delete volumes safely Jump to heading
await client.volumes.delete("training-cache");
sdk.volumes.delete("training-cache")
await sdk.volumes.delete("training-cache")
Deletion is a two-step process:
- The API marks the volume as deleted immediately, which detaches it from new sandbox requests and frees the slug for future reuse.
- A background job waits 24 hours before removing the underlying block storage from the cluster. This grace period allows you to contact support if a volume was removed accidentally.
During the grace period you cannot mount or read the volume.
Snapshots Jump to heading
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.
Creating a snapshot Jump to heading
The workflow is:
- Create a bootable volume from a base image
- Boot a sandbox with that volume as
root(writable) - Install software
- Snapshot the volume
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
Booting from a snapshot Jump to heading
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.
Listing snapshots Jump to heading
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
Creating a volume from a snapshot Jump to heading
Create a new writable volume from a snapshot:
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.
Deleting snapshots Jump to heading
await client.snapshots.delete("my-toolchain-snapshot");
deno sandbox snapshots delete my-toolchain-snapshot
Volumes vs Snapshots Jump to heading
| 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 |