Skip to content

Modal.Volume reference

Source: packages/modal/src/CreateVolume.ts

Create volumes by name at runtime: one per user, session or task. Modal’s native shape is get-or-create by name, so getOrCreate is idempotent and safe to call on every request.

Bind it to a Modal.Environment to keep these runtime objects in their own namespace (or to nothing, for the workspace’s default environment). They aren’t in Alchemy state: deleting the environment removes them.

Objects created at run time are tagged with the stack, stage and binding (alchemy::stack, alchemy::stage, alchemy::id) and are not deleted when the stack is destroyed. A Modal volume has only a name, so the tags become its name prefix, Modal.runtimePrefix({ stack, stage, id }): list them with modal volume list and delete the ones whose name starts with it.

import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Modal from "@alchemy.run/modal";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import { HttpServerRequest } from "effect/http/HttpServerRequest";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import { Agents, Coder } from "./Coder.ts";
export default class Api extends Cloudflare.Worker<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const volumes = yield* Modal.CreateVolume(Agents);
const sandboxes = yield* Modal.CreateSandbox(Coder);
return {
fetch: Effect.gen(function* () {
const request = yield* HttpServerRequest;
const user = request.headers["x-user"] ?? "anonymous";
const home = yield* volumes.getOrCreate(`user-${user}`);
yield* home.writeFile("/notes.md", "hello");
const sandbox = yield* sandboxes.create({ mounts: [{ volume: home, path: "/home/user" }] });
return HttpServerResponse.text("ok");
}).pipe(Effect.orDie),
};
}).pipe(Effect.provide(Layer.mergeAll(Modal.CreateVolumeHttp, Modal.CreateSandboxHttp))),
) {}

Source: packages/modal/src/CreateVolumeHttp.ts Kind: Layer · Provides: Modal.CreateVolume

CreateVolume over Modal’s API. Grants the host’s identity (a scoped Modal.ServiceUser) the contributor role on the environment.

Source: packages/modal/src/MountBucket.ts Kind: Layer · Provides: Modal.MountBucket

MountBucket: binds the entry into a Modal runtime’s mounts, or resolves it for sandboxes.create in any other runtime.

Source: packages/modal/src/MountVolume.ts Kind: Layer · Provides: Modal.MountVolume

MountVolume: binds the entry into a Modal runtime’s mounts, or grants another runtime’s identity access to the volume’s environment.

Source: packages/modal/src/ReadVolume.ts

Read a Modal Volume’s files from any runtime (a Worker, a Lambda, a Modal sandbox) without mounting it: list directories and read files over Modal’s volume API.

import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Modal from "@alchemy.run/modal";
import * as Effect from "effect/Effect";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import { Workspace } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const volume = yield* Modal.ReadVolume(Workspace);
return {
fetch: Effect.gen(function* () {
const files = yield* volume.listFiles("/");
const readme = yield* volume.readFileString("/README.md");
return yield* HttpServerResponse.json({ files, readme });
}).pipe(Effect.orDie),
};
}).pipe(Effect.provide(Modal.ReadVolumeHttp)),
) {}

Source: packages/modal/src/ReadVolumeHttp.ts Kind: Layer · Provides: Modal.ReadVolume

ReadVolume over Modal’s volume API. Grants the host’s identity (a scoped Modal.ServiceUser) the viewer role on the volume’s environment.

Source: packages/modal/src/ReadWriteVolume.ts

Read and write a Modal Volume’s files from any runtime without mounting it.

import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Modal from "@alchemy.run/modal";
import * as Effect from "effect/Effect";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import { Workspace } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const volume = yield* Modal.ReadWriteVolume(Workspace);
return {
fetch: Effect.gen(function* () {
yield* volume.writeFile("/hello.txt", "hello");
const text = yield* volume.readFileString("/hello.txt");
return HttpServerResponse.text(text);
}).pipe(Effect.orDie),
};
}).pipe(Effect.provide(Modal.ReadWriteVolumeHttp)),
) {}

Source: packages/modal/src/ReadWriteVolumeHttp.ts Kind: Layer · Provides: Modal.ReadWriteVolume

ReadWriteVolume over Modal’s volume API. Grants the host’s identity (a scoped Modal.ServiceUser) the contributor role on the volume’s environment.

Source: packages/modal/src/Volume.ts

A Modal Volume: a persistent, shared filesystem that Sandboxes and Functions mount at a path. Writes from one container become visible to others after a commit (Sandboxes commit when they exit).

Declare a Volume here for data every deployment shares, such as a model cache or a dataset. For one volume per user or session, create them at runtime with CreateVolume; to read and write files from a Worker or Lambda without a sandbox, bind ReadWriteVolume.

Modal volumes have no tags. Ownership is inferred from Alchemy state: a volume found under an explicit name without prior state is reported as unowned.

A volume with a generated name

import * as Modal from "@alchemy.run/modal";
export const Cache = Modal.Volume("Cache", {});

A named volume in an environment

import * as Modal from "@alchemy.run/modal";
export const Agents = Modal.Environment("Agents", {});
export const Models = Modal.Volume("Models", { name: "model-weights", environment: Agents });
// construction phase
const cache = yield* Modal.MountVolume(Cache, { path: "/cache" });
const sandboxes = yield* Modal.CreateSandbox(Coder);
// per request
const sandbox = yield* sandboxes.create({ mounts: [cache] });
import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Modal from "@alchemy.run/modal";
import * as Effect from "effect/Effect";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import { Cache } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const cache = yield* Modal.ReadWriteVolume(Cache);
return {
fetch: Effect.gen(function* () {
yield* cache.writeFile("/hello.txt", "hello");
const text = yield* cache.readFileString("/hello.txt");
return HttpServerResponse.text(text);
}).pipe(Effect.orDie),
};
}).pipe(Effect.provide(Modal.ReadWriteVolumeHttp)),
) {}

Volume.lookup references a volume Alchemy doesn’t manage (created with the Modal CLI or by another stack). It is read during plan/deploy, never created, updated or deleted.

const weights = Modal.Volume.lookup({ name: "model-weights" });

Source: packages/modal/src/WriteVolume.ts

Write a Modal Volume’s files from any runtime without mounting it: upload, remove and copy files over Modal’s volume API. Sandboxes that mount the volume see the changes after they reload it.

import * as Cloudflare from "@alchemy.run/cloudflare";
import * as Modal from "@alchemy.run/modal";
import * as Effect from "effect/Effect";
import * as HttpServerResponse from "effect/http/HttpServerResponse";
import { Workspace } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()(
"Api",
{ main: import.meta.url },
Effect.gen(function* () {
const volume = yield* Modal.WriteVolume(Workspace);
return {
fetch: Effect.gen(function* () {
yield* volume.writeFile("/inbox/task.json", JSON.stringify({ repo: "alchemy" }));
return HttpServerResponse.text("written");
}).pipe(Effect.orDie),
};
}).pipe(Effect.provide(Modal.WriteVolumeHttp)),
) {}

Source: packages/modal/src/WriteVolumeHttp.ts Kind: Layer · Provides: Modal.WriteVolume

WriteVolume over Modal’s volume API. Grants the host’s identity (a scoped Modal.ServiceUser) the contributor role on the volume’s environment.