# How to back up and restore a sandbox volume Volumes are backed up daily or on your own schedule. `volumes.backup(id)` makes a backup now. `volumes.restore(backupId)` restores it. **On Runtime, a volume outlives the server it lives on.** A volume is a disk that outlives sandboxes. It stays on one server, and it is copied off that server every day without a request from you. The copy is encrypted with a key that belongs to your organization alone. A restore can land on any server in the region. Backups are incremental. They cost $0.02 per decimal GB per 30-day month of what they store. A backup made before this price keeps $0.012 until 7 November 2026. For example, a week of daily backups that store 3 GB in all costs $0.06 a month ([storage and backups](/docs/storage#volume-backups)). ## Back up now ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); const volume = await runtime.volumes.create({ sizeMiB: 10_240, name: "data" }); await using sbx = await runtime.sandboxes.create({ volumes: [{ volumeId: volume.id, path: "/data" }], }); await sbx.exec("sudo chown runtime /data && echo kept > /data/note.txt && sync", { check: true }); const backup = await runtime.volumes.backup(volume.id, { retentionDays: 30 }); // waits up to a minute console.log(backup.id, backup.state, backup.storedBytes); ``` ```python check from withruntime import Runtime runtime = Runtime() volume = runtime.volumes.create(10_240, name="data") with runtime.sandboxes.create(volumes=[{"volume_id": volume["id"], "path": "/data"}]) as sbx: sbx.exec("sudo chown runtime /data && echo kept > /data/note.txt && sync", check=True) backup = runtime.volumes.backup(volume["id"], retention_days=30) print(backup["id"], backup["state"]) ``` ```bash no-run runtime volumes backup "${vol}" --retention-days 30 # prints the backup id runtime volumes backups "${vol}" # newest first ``` A backup is `pending` until its copy is written off the server, read back, and checked. Then it is `ready`. The volume's `backedUp` turns `true` at that point. `backups.lastReadyAt` shows when the newest backup was taken. ## Restore it A restore is always a new volume. It has the size of the backup, and it is created in the same region, on whichever server has room. The original is never changed: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); const restored = await runtime.volumes.restore("", { name: "data-restored" }); console.log(restored.state, restored.restoredFrom); // "creating" until every byte is checked await using sbx = await runtime.sandboxes.create({ volumes: [{ volumeId: restored.id, path: "/data" }], }); console.log((await sbx.exec("cat /data/note.txt")).stdout); ``` ```python check from withruntime import Runtime runtime = Runtime() restored = runtime.volumes.restore("", name="data-restored") print(restored["state"], restored["restoredFrom"]) ``` ```bash no-run runtime volumes restore "${backup}" --name data-restored ``` The restored volume is ready once every byte has been downloaded and checked. Attach it to a new sandbox as you would any other volume. ## Daily backups and how long they are kept ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.volumes.setBackupPolicy("", { daily: true, retentionDays: 14 }); for await (const each of await runtime.volumes.backups({ volumeId: "" })) console.log(each.id, each.trigger, each.readyAt, each.expiresAt); ``` ```bash no-run runtime volumes backup-policy "${vol}" --daily on --retention-days 14 runtime volumes backup-rm "${backup}" ``` ## Backups on your own schedule A volume can be backed up every N minutes (15 or more), or on a five-field cron schedule in UTC. Keep its backups by count: the last N, and the newest in each of the newest N hours, days, weeks (from Monday), months and years. A backup that any count keeps is kept. The newest ready backup is also kept. ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); // Every hour; keep 24 hourly, 7 daily and 4 weekly backups. await runtime.volumes.setBackupPolicy("", { schedule: { everyMinutes: 60 }, keep: { hourly: 24, daily: 7, weekly: 4 }, }); // 02:30 UTC on weekdays; back to daily with schedule: null. await runtime.volumes.setBackupPolicy("", { schedule: { cron: "30 2 * * 1-5" } }); await runtime.volumes.setBackupPolicy("", { schedule: null }); ``` ```bash no-run runtime volumes backup-policy "${vol}" --every 60 --keep hourly=24,daily=7,weekly=4 runtime volumes backup-policy "${vol}" --cron "30 2 * * 1-5" runtime volumes backup-policy "${vol}" --no-schedule ``` The volume reports its `backups.schedule`, `keep` and `nextAt`. A backup made on the schedule has `trigger: "scheduled"`. It has no `expiresAt` while the counts keep it. An agent does the same with the `runtime_volumes_backup` MCP tool (`create`, `list`, `get`, `policy`, `delete`). It restores with `runtime_volumes`, action `create`, and `fromBackup`. ## The rules | What | How it works | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Daily backup | On for every volume, first taken an hour after it is created; `daily: false` turns it off | | Your own schedule | Every 15 to 525,600 minutes from 1970-01-01 UTC, or a cron in UTC; replaces the daily backup until you set `schedule: null` | | Retention | 7 days unless you set 1 to 365, per volume or per backup; on a schedule, the keep counts (each 0 to 1,000) | | On request | `backup(id)` makes one now and waits up to a minute for it to be ready | | What is stored | Only what changed since an earlier backup of the same volume; empty space not at all | | Consistency | A point in time, as a disk is after a power cut | | Encryption | Your organization's own data key; every piece is checked when read back | | Deleting the volume | Its backups stay until each one's retention ends; a scheduled one stays the volume's retention days from then | | Limit | 200 volume backups per organization at a time | | Price | $0.02 per decimal GB per 30-day month ($0.012 until 7 November 2026 for one made before), on `storedBytes`, once the copy is ready | The volume itself is charged on its full size, at 153 microdollars per GiB-hour, or about $0.11 per GiB a month. An account without credit keeps its first 10 GiB of volumes free ([pricing](/docs/pricing#snapshots-images-and-volumes)). ## Mistakes and how Runtime handles them - **Backing up in the middle of a write.** A backup holds what the disk held at that moment. It does not hold what a program still had in memory. For a clean point, stop the sandbox first. A stop writes out what the sandbox wrote to its volumes, and a stop that waits returns once the volumes are free. Otherwise, run `sync` or stop the database before you run `backup`. - **Running out of time or credit.** Runtime freezes the sandbox's programs just before the end. It then writes out what they wrote to its volumes, as a stop does, at no charge. - **Losing the server.** If a volume's server is lost, the volume goes with it. Its error names the newest backup to restore from. - **Expecting a restore to overwrite.** A restore never overwrites anything. It creates a new volume with `restoredFrom` set, so the damaged volume is still there to compare. - **Snapshotting instead.** A sandbox with volumes cannot be snapshotted. Back up the volume, and rebuild the sandbox from an image. - **Keeping data on the sandbox's own disk.** A sandbox's disk has no copy off its server. Keep what you cannot rebuild on a volume. ## Related - [Mount an S3 bucket](/how-to/mount-an-s3-bucket) for data that already lives in object storage. - [Pause and resume a sandbox](/how-to/pause-and-resume-a-sandbox) to keep a whole machine, memory included. - [What is a sandbox snapshot?](/glossary/sandbox-snapshot) ## Start ```bash no-run npx withruntime volumes create --size-mib 1024 --name trial-data ``` A new account gets 100 free hours of a 1 GB machine in its first 30 days and 10 GiB of free volume storage, with no card. The first command prints a link to approve in your browser. Facts on this page were checked on 26 October 2026.