Images
An image is the filesystem a Modal container starts from. Modal builds it on its own builders, so a deploy needs no Docker on your machine, and it caches each build by its inputs.
An image builds on another
Section titled “An image builds on another”Each image starts from a registry image or from another image, and adds its own layer. A warm base runs your setup once, at deploy, so every sandbox starts with the work done:
Build from a registry image
Section titled “Build from a registry image”import * as Modal from "@alchemy.run/modal";
export const Coder = Modal.App("Coder", {});
export const Node = Modal.Image("Node", { app: Coder, image: "node:22-bookworm", commands: ["RUN apt-get update && apt-get install -y git ripgrep"],});commands are Dockerfile lines, run on top of the registry image.
Build from a Dockerfile
Section titled “Build from a Dockerfile”import * as Dockerfile from "@alchemy.run/docker/Dockerfile";import * as Modal from "@alchemy.run/modal";
export const Coder = Modal.App("Coder", {});
export const Python = Modal.Image("Python", { app: Coder, dockerfile: Dockerfile.inline` FROM python:3.12-slim RUN pip install pandas `,});Modal’s builder isn’t Docker. Multi-stage builds, BuildKit mounts, EXPOSE, HEALTHCHECK, LABEL, ONBUILD, STOPSIGNAL and VOLUME fail at plan, naming the line. USER is ignored: containers run as root.
A Dockerfile path works too: dockerfile: "./sandbox/Dockerfile". Files its COPY lines read are uploaded from the Dockerfile’s directory, or from context.
Install a repository into a warm base
Section titled “Install a repository into a warm base”export const Warm = Modal.Image("Warm", { app: Coder, from: Node, run: [ "git clone https://github.com/alchemy-run/alchemy /work", "cd /work && corepack enable && pnpm install", ],});run executes in a sandbox at deploy, then saves its files as the image. Changing run or the base builds a new one.
Build images while your app runs
Section titled “Build images while your app runs”For an image per repository or per user, bind CreateImage and build at run time:
const images = yield* Modal.CreateImage(Coder);const image = yield* images.build({ image: "node:22-bookworm", commands: [`RUN git clone https://github.com/${repo} /work`],});const sandbox = yield* sandboxes.create({ image });Modal caches builds by content, so the same inputs return the same image.