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
modal.volumes.fromName(name, params?)
Reference a Volume by name.
Optional parameters
If true, creates the Volume if it doesn’t exist.
// Reference existing volume
const volume = await modal.volumes.fromName("my-data");
// Create if missing
const volume = await modal.volumes.fromName("my-data", {
createIfMissing: true,
});
modal.volumes.ephemeral(params?)
Create a temporary, nameless Volume. It persists until closeEphemeral() is called or the process exits.
The ephemeral Volume object.
const volume = await modal.volumes.ephemeral();
// Use the volume...
// Clean up when done
volume.closeEphemeral();
modal.volumes.delete(name, params?)
Delete a named Volume.
Name of the Volume to delete.
Optional parameters
If true, don’t throw an error if the Volume doesn’t exist.
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
Unique identifier for the Volume.
Name of the Volume, if it was looked up by name.
Whether the Volume is configured to mount as read-only.
Methods
readOnly()
Return a new Volume instance configured to mount as read-only.
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",
});