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+
616Persistent volumes let you attach regional block storage to a sandbox so data
717survives process restarts and new connections. They are ideal for package
818caches, build artifacts, SQLite databases, or any workflow that needs a small
919amount 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
103106The volumes API returns paginated results and can fetch a single record by slug
104107or UUID.
@@ -108,38 +111,33 @@ or UUID.
108111
109112``` tsx
110113const 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
127125page = 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
138136page = 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
149147from the underlying cluster. It can lag a few minutes behind reality, so always
150148size 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(
271276Mounts behave like regular directories. You can create subfolders, write binary
272277files, 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
308313During 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