Skip to main content
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:
specific.hcl
service "api" {
  build = build.api
  command = "node server.js"

  volume "uploads" {}

  env = {
    UPLOADS_DIR = volume.uploads.path
  }
}

Attributes

AttributeDescription
pathAbsolute path to the volume directory.

How it works

  • In production: each volume is backed by a persistent disk, and path resolves 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:
specific.hcl
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.