Skip to main content
Volumes provide persistent storage that can be mounted in Modal Functions and Sandboxes. Data written to a Volume persists across executions.

Access the Volumes API

import { ModalClient } from "modal";

const modal = new ModalClient();
const volume = await modal.volumes.fromName("my-volume");

Methods

Reference a Volume by name.
name
string
required
Name of the Volume.
params
VolumeFromNameParams
Optional parameters
return
Promise<Volume>
The Volume object.
// Reference existing volume
const volume = await modal.volumes.fromName("my-data");

// Create if missing
const volume = await modal.volumes.fromName("my-data", {
  createIfMissing: true,
});
Create a temporary, nameless Volume. It persists until closeEphemeral() is called or the process exits.
params
VolumeEphemeralParams
Optional parameters
return
Promise<Volume>
The ephemeral Volume object.
const volume = await modal.volumes.ephemeral();

// Use the volume...

// Clean up when done
volume.closeEphemeral();
Delete a named Volume.
name
string
required
Name of the Volume to delete.
params
VolumeDeleteParams
Optional parameters
await modal.volumes.delete("old-volume");

// Don't error if it doesn't exist
await modal.volumes.delete("maybe-volume", { allowMissing: true });
Deletion is irreversible and will affect any Apps currently using the Volume.

Volume object

Properties

volumeId
string
Unique identifier for the Volume.
name
string | undefined
Name of the Volume, if it was looked up by name.
isReadOnly
boolean
Whether the Volume is configured to mount as read-only.

Methods

readOnly()

Return a new Volume instance configured to mount as read-only.
return
Volume
A read-only Volume instance.
const volume = await modal.volumes.fromName("shared-data");
const roVolume = volume.readOnly();

// Mount as read-only
const sandbox = await modal.sandboxes.create(app, image, {
  volumes: { "/data": roVolume },
});

closeEphemeral()

Delete an ephemeral Volume. Only works with ephemeral Volumes.
const volume = await modal.volumes.ephemeral();

// Use the volume...

volume.closeEphemeral(); // Clean up
Throws InvalidError if called on a non-ephemeral Volume.

Example: Persist data across Sandbox runs

import { ModalClient } from "modal";

const modal = new ModalClient();

const app = await modal.apps.fromName("data-processor", {
  createIfMissing: true,
});

const volume = await modal.volumes.fromName("processed-data", {
  createIfMissing: true,
});

const image = modal.images.fromRegistry("python:3.13");

// First run: Write data
const writer = await modal.sandboxes.create(app, image, {
  volumes: { "/data": volume },
});

const writeProc = await writer.exec([
  "sh",
  "-c",
  "echo 'Hello from first run' > /data/output.txt",
]);
await writeProc.wait();
await writer.terminate();

// Second run: Read data
const reader = await modal.sandboxes.create(app, image, {
  volumes: { "/data": volume },
});

const readProc = await reader.exec(["cat", "/data/output.txt"]);
const content = await readProc.stdout.readText();
console.log(content); // "Hello from first run"

await reader.terminate();

Example: Share data between Functions and Sandboxes

import { ModalClient } from "modal";

const modal = new ModalClient();

const app = await modal.apps.fromName("ml-pipeline", {
  createIfMissing: true,
});

// Create a volume for model artifacts
const modelVolume = await modal.volumes.fromName("model-artifacts", {
  createIfMissing: true,
});

// Mount as read-only for inference
const roModelVolume = modelVolume.readOnly();

const image = modal.images
  .fromRegistry("python:3.13")
  .dockerfileCommands(["RUN pip install torch transformers"]);

// Sandbox for training (read-write)
const trainer = await modal.sandboxes.create(app, image, {
  volumes: { "/models": modelVolume },
  gpu: "A100",
});

// Sandbox for inference (read-only)
const inferencer = await modal.sandboxes.create(app, image, {
  volumes: { "/models": roModelVolume },
  gpu: "T4",
});

Build docs developers (and LLMs) love