Volumes
Persistent directories that survive deploys and restarts.
Volumes provide a directory that persists across deployments and restarts, useful for file uploads, caches, and other data that needs to survive.
Volumes are defined as sub-blocks within a service. Each volume has a name and exposes a path attribute that resolves to the directory path:
service "api" {
build = build.api
command = "node server.js"
volume "uploads" {}
env = {
UPLOADS_DIR = volume.uploads.path
}
}
Attributes
| Attribute | Description |
|---|---|
path |
Absolute path to the volume directory. |
How it works
- In production: each volume is backed by a persistent disk, and
pathresolves to/volumes/{name}inside the container. - In development (
specific dev): each volume maps to a local directory at.specific/keys/.../data/volumes/{service}/{name}/.
Volume data persists across deployments and dev server restarts.
Multiple volumes
A service can define multiple volumes:
service "api" {
build = build.api
command = "node server.js"
volume "uploads" {}
volume "cache" {}
env = {
UPLOADS_DIR = volume.uploads.path
CACHE_DIR = volume.cache.path
}
}
Example usage (Node.js)
import fs from "fs";
import path from "path";
const uploadsDir = process.env.UPLOADS_DIR;
// Write a file
fs.writeFileSync(path.join(uploadsDir, "myfile.txt"), "Hello, world!");
// Read it back (persists across restarts)
const content = fs.readFileSync(path.join(uploadsDir, "myfile.txt"), "utf8");
Preview environments
Preview environments get an instant copy-on-write clone of each volume, so a preview’s service starts on an exact copy of the parent’s data with no extra configuration, and writes to the clone never affect the parent.