Skip to content

Commit f8f098e

Browse files
authored
Add docs for snapshots (#2877)
1 parent b1acc6b commit f8f098e

File tree

3 files changed

+207
-47
lines changed

3 files changed

+207
-47
lines changed

sandbox/_data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const sidebar = [
3535
href: "/sandbox/apps/",
3636
},
3737
{
38-
title: "Volumes",
38+
title: "Volumes & Snapshots",
3939
href: "/sandbox/volumes/",
4040
},
4141
{

sandbox/cli.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -257,35 +257,26 @@ deno sandbox volumes delete my-volume
257257

258258
## Managing snapshots
259259

260-
Snapshots allow you to preserve the current state of a volume as a point-in-time
261-
copy.
260+
Snapshots are read-only images created from volumes. Use them to pre-install
261+
software once, then boot new sandboxes instantly with everything ready. See
262+
[Volumes & Snapshots](./volumes/) for the full workflow.
262263

263264
### Creating snapshots
264265

265-
Create a new snapshot from an existing volume:
266+
Create a snapshot from an existing volume:
266267

267268
```bash
268269
deno sandbox snapshots create my-volume my-snapshot
269270
```
270271

271-
You can also use the `volumes snapshot` command:
272-
273-
```bash
274-
deno sandbox volumes snapshot my-volume my-snapshot
275-
```
276-
277272
### Listing snapshots
278273

279274
List all snapshots in your organization:
280275

281276
```bash
282-
deno sandbox snapshots list
283-
```
284-
285-
You can also search for specific snapshots:
286-
287-
```bash
288-
deno sandbox snapshots list my-snapshot
277+
$ deno sandbox snapshots list
278+
ID SLUG REGION ALLOCATED BOOTABLE
279+
snp_ord_spmbe47dysccpy277ma6 my-snapshot ord 217.05 MiB TRUE
289280
```
290281

291282
### Deleting snapshots

sandbox/volumes.md

Lines changed: 199 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
---
2-
title: "Persistent Volumes"
3-
description: "Mount block storage into Deno Sandbox to keep state between sessions"
2+
title: "Volumes & Snapshots"
3+
description: "Persistent storage and bootable images for Deno Sandbox"
44
---
55

6+
Deno Sandbox provides two storage primitives:
7+
8+
- **Volumes** – read-write block storage. Use for caches, databases, and
9+
artifacts that persist across sessions.
10+
- **Snapshots** – read-only images created from volumes. Use for pre-installing
11+
software so sandboxes boot instantly with everything ready. You can also
12+
create new volumes from snapshots.
13+
14+
## Volumes
15+
616
Persistent volumes let you attach regional block storage to a sandbox so data
717
survives process restarts and new connections. They are ideal for package
818
caches, build artifacts, SQLite databases, or any workflow that needs a small
919
amount of durable storage without promoting code to a full Deno Deploy app.
1020

11-
:::note
12-
13-
Persistent volumes are currently in private beta. Contact
14-
[support](mailto:support@deno.com) to request access to this feature
15-
16-
:::
17-
18-
## Provision storage
21+
### Provision storage
1922

2023
<deno-tabs group-id="sandbox-sdk">
2124
<deno-tab value="js" label="JavaScript" default>
@@ -98,7 +101,7 @@ print(volume)
98101
| `region` || Must match an available sandbox region (`"ord"` or `"ams"` today). Only sandboxes in the same region can mount the volume. |
99102
| `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. |
100103

101-
## Inspect and search volumes
104+
### Inspect and search volumes
102105

103106
The volumes API returns paginated results and can fetch a single record by slug
104107
or UUID.
@@ -108,38 +111,33 @@ or UUID.
108111

109112
```tsx
110113
const page = await client.volumes.list({ search: "training" });
111-
for (const info of page.items) {
112-
console.log(
113-
info.slug,
114-
formatBytes(info.used),
115-
"of",
116-
formatBytes(info.capacity),
117-
);
114+
for (const vol of page.items) {
115+
console.log(vol.slug, vol.used, vol.capacity);
118116
}
119117

120-
const latest = await client.volumes.get("training-cache");
118+
const vol = await client.volumes.get("training-cache");
121119
```
122120

123121
</deno-tab>
124122
<deno-tab value="python" label="Python">
125123

126124
```py
127125
page = sdk.volumes.list(search="training")
128-
for info in page.items:
129-
print(f"{info['slug']} {info['used']} of {info['capacity']}")
126+
for vol in page.items:
127+
print(f"{vol['slug']} {vol['used']} {vol['capacity']}")
130128

131-
latest = sdk.volumes.get("training-cache")
129+
vol = sdk.volumes.get("training-cache")
132130
```
133131

134132
</deno-tab>
135133
<deno-tab value="python-async" label="Python (Async)">
136134

137135
```py
138136
page = await sdk.volumes.list(search="training")
139-
async for info in page:
140-
print(f"{info['slug']} {info['used']} of {info['capacity']}")
137+
async for vol in page:
138+
print(f"{vol['slug']} {vol['used']} {vol['capacity']}")
141139

142-
latest = await sdk.volumes.get("training-cache")
140+
vol = await sdk.volumes.get("training-cache")
143141
```
144142

145143
</deno-tab>
@@ -149,11 +147,18 @@ The `used` field reports the most recent estimate the control plane received
149147
from the underlying cluster. It can lag a few minutes behind reality, so always
150148
size volumes with headroom.
151149

152-
## Mount volumes inside a sandbox
150+
### Mount volumes inside a sandbox
151+
152+
Pass a `volumes` mapping when creating a sandbox. Keys are mount paths and
153+
values are either the volume slug or ID. The sandbox and volume **must be in the
154+
same region**.
155+
156+
:::note
153157

154-
Pass a volumes mapping when creating a sandbox. Keys are mount paths and values
155-
are either the volume slug or ID. The sandbox and volume **must live in the same
156-
region**.
158+
`Sandbox.create()` and `client.sandboxes.create()` are equivalent—use whichever
159+
fits your code style.
160+
161+
:::
157162

158163
<deno-tabs group-id="sandbox-sdk">
159164
<deno-tab value="js" label="JavaScript" default>
@@ -271,7 +276,7 @@ async with sdk.sandbox.create(
271276
Mounts behave like regular directories. You can create subfolders, write binary
272277
files, or execute programs directly from the volume.
273278

274-
## Delete volumes safely
279+
### Delete volumes safely
275280

276281
<deno-tabs group-id="sandbox-sdk">
277282
<deno-tab value="js" label="JavaScript" default>
@@ -306,3 +311,167 @@ Deletion is a two-step process:
306311
was removed accidentally.
307312

308313
During the grace period you cannot mount or read the volume.
314+
315+
## Snapshots
316+
317+
Snapshots are read-only images created from volumes. When a sandbox boots with a
318+
snapshot as its root, the entire filesystem is replaced with the snapshot
319+
contents. Run `apt-get install` or `npm install` once, snapshot the result, and
320+
every future sandbox starts instantly with everything already installed.
321+
322+
### Creating a snapshot
323+
324+
The workflow is:
325+
326+
1. Create a **bootable volume** from a base image
327+
2. Boot a sandbox with that volume as `root` (writable)
328+
3. Install software
329+
4. Snapshot the volume
330+
331+
Sandboxes booted from the snapshot start instantly with everything installed.
332+
333+
A volume is **bootable** when created with the `from` option. Currently
334+
`builtin:debian-13` is the only available base image.
335+
336+
<deno-tabs group-id="sandbox-sdk">
337+
<deno-tab value="js" label="JavaScript" default>
338+
339+
```tsx
340+
import { Client } from "@deno/sandbox";
341+
342+
const client = new Client();
343+
344+
// 1. Create a bootable volume
345+
const volume = await client.volumes.create({
346+
region: "ord",
347+
slug: "my-toolchain",
348+
capacity: "10GiB",
349+
from: "builtin:debian-13",
350+
});
351+
352+
// 2. Boot a sandbox with the volume as root (writable)
353+
await using sandbox = await client.sandboxes.create({
354+
region: "ord",
355+
root: volume.slug,
356+
});
357+
358+
// 3. Install software
359+
await sandbox.sh`apt-get update && apt-get install -y nodejs npm`;
360+
await sandbox.sh`npm install -g typescript`;
361+
362+
// 4. Snapshot the volume
363+
const snapshot = await client.volumes.snapshot(volume.id, {
364+
slug: "my-toolchain-snapshot",
365+
});
366+
```
367+
368+
</deno-tab>
369+
<deno-tab value="cli" label="CLI">
370+
371+
```bash
372+
# Create snapshot from a volume
373+
deno sandbox snapshots create my-toolchain my-toolchain-snapshot
374+
```
375+
376+
</deno-tab>
377+
</deno-tabs>
378+
379+
### Booting from a snapshot
380+
381+
Once you have a snapshot, use it as the `root` when creating new sandboxes. The
382+
sandbox must be created in the same region as the snapshot:
383+
384+
<deno-tabs group-id="sandbox-sdk">
385+
<deno-tab value="js" label="JavaScript" default>
386+
387+
```tsx
388+
await using sandbox = await client.sandboxes.create({
389+
region: "ord",
390+
root: "my-toolchain-snapshot", // snapshot slug or ID
391+
});
392+
393+
// TypeScript and Node.js are already installed
394+
await sandbox.sh`tsc --version`;
395+
await sandbox.sh`node --version`;
396+
```
397+
398+
</deno-tab>
399+
</deno-tabs>
400+
401+
The sandbox boots with the snapshot's filesystem as its root. Any writes during
402+
the session are ephemeral—they don't modify the snapshot.
403+
404+
### Listing snapshots
405+
406+
<deno-tabs group-id="sandbox-sdk">
407+
<deno-tab value="js" label="JavaScript" default>
408+
409+
```tsx
410+
const page = await client.snapshots.list();
411+
for (const snap of page.items) {
412+
console.log(snap.slug, snap.region, snap.bootable);
413+
}
414+
```
415+
416+
</deno-tab>
417+
<deno-tab value="cli" label="CLI">
418+
419+
```bash
420+
$ deno sandbox snapshots list
421+
ID SLUG REGION ALLOCATED BOOTABLE
422+
snp_ord_spmbe47dysccpy277ma6 my-toolchain-snapshot ord 217.05 MiB TRUE
423+
```
424+
425+
</deno-tab>
426+
</deno-tabs>
427+
428+
### Creating a volume from a snapshot
429+
430+
Create a new writable volume from a snapshot:
431+
432+
<deno-tabs group-id="sandbox-sdk">
433+
<deno-tab value="js" label="JavaScript" default>
434+
435+
```tsx
436+
const volume = await client.volumes.create({
437+
region: "ord",
438+
slug: "my-toolchain-fork",
439+
capacity: "10GiB",
440+
from: "my-toolchain-snapshot",
441+
});
442+
```
443+
444+
</deno-tab>
445+
</deno-tabs>
446+
447+
The new volume contains the snapshot's contents and is fully writable. Use this
448+
to modify a snapshot's contents, then snapshot again.
449+
450+
### Deleting snapshots
451+
452+
<deno-tabs group-id="sandbox-sdk">
453+
<deno-tab value="js" label="JavaScript" default>
454+
455+
```tsx
456+
await client.snapshots.delete("my-toolchain-snapshot");
457+
```
458+
459+
</deno-tab>
460+
<deno-tab value="cli" label="CLI">
461+
462+
```bash
463+
deno sandbox snapshots delete my-toolchain-snapshot
464+
```
465+
466+
</deno-tab>
467+
</deno-tabs>
468+
469+
### Volumes vs Snapshots
470+
471+
| Feature | Volumes | Snapshots |
472+
| -------------- | ----------------------------------- | ---------------------------------- |
473+
| Access | Read-write | Read-only |
474+
| Mount point | Any path, or root if bootable | Root filesystem only |
475+
| Use case | Caches, databases, install software | Pre-installed software, toolchains |
476+
| Concurrent use | One sandbox at a time | Many sandboxes simultaneously |
477+
| Region | Must match sandbox region | Must match sandbox region |

0 commit comments

Comments
 (0)