Modal.Volume reference
CreateVolume
Section titled “CreateVolume”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.
CreateVolume: One volume per user
Section titled “CreateVolume: One volume per user”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))),) {}CreateVolumeHttp
Section titled “CreateVolumeHttp”Source:
packages/modal/src/CreateVolumeHttp.tsKind: Layer · Provides:Modal.CreateVolume
CreateVolume over Modal’s API. Grants the host’s identity (a scoped
Modal.ServiceUser) the contributor role on the environment.
MountBucketLive
Section titled “MountBucketLive”Source:
packages/modal/src/MountBucket.tsKind: Layer · Provides:Modal.MountBucket
MountBucket: binds the entry into a Modal runtime’s mounts, or
resolves it for sandboxes.create in any other runtime.
MountVolumeLive
Section titled “MountVolumeLive”Source:
packages/modal/src/MountVolume.tsKind: 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.
ReadVolume
Section titled “ReadVolume”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.
ReadVolume: Bind a volume
Section titled “ReadVolume: Bind a volume”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)),) {}ReadVolumeHttp
Section titled “ReadVolumeHttp”Source:
packages/modal/src/ReadVolumeHttp.tsKind: 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.
ReadWriteVolume
Section titled “ReadWriteVolume”Source:
packages/modal/src/ReadWriteVolume.ts
Read and write a Modal Volume’s files from any runtime without mounting it.
ReadWriteVolume: Bind a volume
Section titled “ReadWriteVolume: Bind a volume”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)),) {}ReadWriteVolumeHttp
Section titled “ReadWriteVolumeHttp”Source:
packages/modal/src/ReadWriteVolumeHttp.tsKind: 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.
Volume
Section titled “Volume”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.
Volume: Creating a Volume
Section titled “Volume: Creating a Volume”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 });Volume: Mounting in a Sandbox
Section titled “Volume: Mounting in a Sandbox”// construction phaseconst cache = yield* Modal.MountVolume(Cache, { path: "/cache" });const sandboxes = yield* Modal.CreateSandbox(Coder);// per requestconst sandbox = yield* sandboxes.create({ mounts: [cache] });Volume: Reading files from a Worker
Section titled “Volume: Reading files from a Worker”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: Looking up an existing volume
Section titled “Volume: Looking up an existing volume”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" });WriteVolume
Section titled “WriteVolume”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.
WriteVolume: Bind a volume
Section titled “WriteVolume: Bind a volume”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)),) {}WriteVolumeHttp
Section titled “WriteVolumeHttp”Source:
packages/modal/src/WriteVolumeHttp.tsKind: 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.