Modal.Dict reference
CreateDict
Section titled “CreateDict”Source:
packages/modal/src/CreateDict.ts
Create dicts 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 dict has only a name, so the tags become
its name prefix, Modal.runtimePrefix({ stack, stage, id }): list them
with modal dict list and delete the ones whose name starts with it.
CreateDict: One dict per user
Section titled “CreateDict: One dict 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 dicts = yield* Modal.CreateDict(Agents); const sandboxes = yield* Modal.CreateSandbox(Coder); return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const user = request.headers["x-user"] ?? "anonymous"; const state = yield* dicts.getOrCreate(`state-${user}`); yield* state.put("lastSeen", Date.now()); return HttpServerResponse.text("ok"); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Layer.mergeAll(Modal.CreateDictHttp, Modal.CreateSandboxHttp))),) {}CreateDictHttp
Section titled “CreateDictHttp”Source:
packages/modal/src/CreateDictHttp.tsKind: Layer · Provides:Modal.CreateDict
CreateDict over Modal’s API. Grants the host’s identity (a scoped
Modal.ServiceUser) the contributor role on the environment.
Source:
packages/modal/src/Dict.ts
A Modal Dict: a distributed key-value store shared by every container, Sandbox and client in the workspace. Entries expire 7 days after their last write.
Bind it with ReadDict, WriteDict or ReadWriteDict
to use it from a Worker, Lambda or any other runtime. Values travel as
bytes: the bindings encode them as JSON by default.
Modal dicts have no tags. Ownership is inferred from Alchemy state: a
dict found under an explicit name without prior state is reported as
unowned.
Dict: Creating a Dict
Section titled “Dict: Creating a Dict”A dict with a generated name
import * as Modal from "@alchemy.run/modal";
export const Results = Modal.Dict("Results", {});A named dict in an environment
import * as Modal from "@alchemy.run/modal";
export const Agents = Modal.Environment("Agents", {});export const Sessions = Modal.Dict("Sessions", { name: "sessions", environment: Agents });Dict: Reading and writing from a Worker
Section titled “Dict: Reading and writing 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 { Results } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const results = yield* Modal.ReadWriteDict(Results); return { fetch: Effect.gen(function* () { yield* results.put("last-run", { ok: true }); const last = yield* results.get("last-run"); return yield* HttpServerResponse.json(last ?? null); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Modal.ReadWriteDictHttp)),) {}Dict: Looking up an existing dict
Section titled “Dict: Looking up an existing dict”Dict.lookup references a dict 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 cache = Modal.Dict.lookup({ name: "cache" });ReadDict
Section titled “ReadDict”Source:
packages/modal/src/ReadDict.ts
Read a Modal Dict from any runtime: get, contains, len and entries. Keys and values are JSON.
ReadDict: Bind a dict
Section titled “ReadDict: Bind a dict”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 { Results } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const dict = yield* Modal.ReadDict(Results); return { fetch: Effect.gen(function* () { const last = yield* dict.get("last-run"); return yield* HttpServerResponse.json(last ?? null); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Modal.ReadDictHttp)),) {}ReadDictHttp
Section titled “ReadDictHttp”Source:
packages/modal/src/ReadDictHttp.tsKind: Layer · Provides:Modal.ReadDict
ReadDict over Modal’s API. Grants the host’s identity (a scoped
Modal.ServiceUser) the viewer role on the dict’s environment.
ReadWriteDict
Section titled “ReadWriteDict”Source:
packages/modal/src/ReadWriteDict.ts
Read and write a Modal Dict from any runtime. Keys and values are JSON.
ReadWriteDict: Bind a dict
Section titled “ReadWriteDict: Bind a dict”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 { Results } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const dict = yield* Modal.ReadWriteDict(Results); return { fetch: Effect.gen(function* () { yield* dict.put("hits", ((yield* dict.get<number>("hits")) ?? 0) + 1); return yield* HttpServerResponse.json({ hits: yield* dict.get("hits") }); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Modal.ReadWriteDictHttp)),) {}ReadWriteDictHttp
Section titled “ReadWriteDictHttp”Source:
packages/modal/src/ReadWriteDictHttp.tsKind: Layer · Provides:Modal.ReadWriteDict
ReadWriteDict over Modal’s API. Grants the host’s identity (a scoped
Modal.ServiceUser) the contributor role on the dict’s environment.
WriteDict
Section titled “WriteDict”Source:
packages/modal/src/WriteDict.ts
Write a Modal Dict from any runtime: put, update, pop and clear. Keys and values are JSON.
WriteDict: Bind a dict
Section titled “WriteDict: Bind a dict”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 { Results } from "./Storage.ts";
export default class Api extends Cloudflare.Worker<Api>()( "Api", { main: import.meta.url }, Effect.gen(function* () { const dict = yield* Modal.WriteDict(Results); return { fetch: Effect.gen(function* () { yield* dict.put("last-run", { ok: true }); return HttpServerResponse.text("saved"); }).pipe(Effect.orDie), }; }).pipe(Effect.provide(Modal.WriteDictHttp)),) {}WriteDictHttp
Section titled “WriteDictHttp”Source:
packages/modal/src/WriteDictHttp.tsKind: Layer · Provides:Modal.WriteDict
WriteDict over Modal’s API. Grants the host’s identity (a scoped
Modal.ServiceUser) the contributor role on the dict’s environment.