---
title: "Build a snapshot from an image ref or Dockerfile"
method: POST
path: "/v1/builds"
tags: ["builds"]
---

# Build a snapshot from an image ref or Dockerfile

`POST /v1/builds`

Submits an asynchronous build. The scheduler creates a build VM,
runs `buildah pull` (image-only path) or `buildah bud` (Dockerfile
path) inside it, snapshots the result, and tears the VM down.

At least one of `imageRef` or `dockerfileContent` must be provided.
If `dockerfileContent` is set, the worker writes it verbatim into
`/tmp/buildctx/Dockerfile` — buildah handles multi-stage,
`SHELL`, `RUN --mount`, etc. natively.

For `COPY` instructions that need files, upload the build context
first via `POST /v1/build-contexts/presign` and pass the returned
download URL as `contextDownloadUrl`.

Response is `202 Accepted` with a build ID; poll
`GET /v1/builds/{id}` until `status` is `completed` or `failed`.

## Request body

- CreateBuildRequest — At least one of `imageRef` or `dockerfileContent` must be set. If only `imageRef` is provided, the build VM pulls that image and rsyncs its rootfs over the VM's `/`. If `dockerfileContent` is provided, the build VM writes it verbatim to `/tmp/buildctx/Dockerfile` and runs `buildah bud`.
  - `name` string — Optional human-readable name for the resulting snapshot. If omitted, the build ID is used.
  - `imageRef` string — Docker image reference (e.g. `python:3.13-slim`, `ghcr.io/user/repo:tag`). Used directly on the no-Dockerfile path, and as a fallback `FROM` source otherwise.
  - `dockerfileContent` string — Raw Dockerfile content to feed to `buildah bud` inside the build VM. Multi-stage, `SHELL`, `RUN --mount`, and every standard Dockerfile feature is supported (handled natively by buildah). Container-runtime metadata (`CMD`, `ENTRYPOINT`, `EXPOSE`, `LABEL`, `HEALTHCHECK`) is consumed by buildah but does not surface on the resulting FastVM snapshot — when the snapshot boots, systemd takes over, not the container's CMD.
  - `machineType` string — Machine size identifier (e.g. `c1m2`, `c2m4`). Controls CPU and memory allocation. Must be supplied on launch unless restoring from a snapshot.
  - `diskGiB` integer — Disk size for the build VM. Defaults to 10 GiB if omitted.
  - `contextDownloadUrl` string, uri — Presigned GET URL for a `tar.gz` of the build context. The worker downloads and extracts this into `/tmp/buildctx` before invoking buildah, so `COPY` instructions resolve against the user's files. Obtain via `POST /v1/build-contexts/presign`.

## Response `202`

Build accepted; poll `GET /v1/builds/{id}` for status

- BuildResponse — Build state snapshot. Returned by `POST /v1/builds` (initial `pending` state) and `GET /v1/builds/{id}` (current state on each poll).
  - `id` string, required — Build ID (UUID). Use this to poll status.
  - `name` string
  - `status` string, required — Current state. Known values: `pending` (accepted, not yet started), `running` (worker is executing), `completed` (snapshot is ready), `failed` (build did not produce a snapshot). Additional values may be introduced in future server versions; clients should treat unknown values as "in progress" rather than as hard errors.
  - `snapshotId` string — Set when `status` is `completed`. Fetch the corresponding Snapshot record via `GET /v1/snapshots/{id}`.
  - `imageRef` string, required
  - `progress` string — Human-readable phase string while the build runs (e.g. `creating build VM`, `buildah pull`, `buildah bud`, `applying image`, `settling VM`, `creating snapshot`). Not present after a terminal status.
  - `error` string — Set when `status` is `failed`. Diagnostic from the worker (truncated to ~4 KiB).
  - `createdAt` string, date-time, required

## Other responses

- `400` — Invalid request
- `401` — Missing or invalid credentials
- `403` — Org quota exceeded
- `413` — `contextDownloadUrl` references an object larger than the server-side cap (1 GiB). The cap is also returned as `maxUploadBytes` from `POST /v1/build-contexts/presign`, so the SDK can advise users before upload — this 413 is the authoritative server-side enforcement.
- `500` — Internal server error
- `501` — File staging is not configured on this cluster (no `FILE_STAGING_BUCKET`). Returned only when `contextDownloadUrl` is supplied — builds without a context work fine on staging-disabled clusters.

## Changes

- **2026-05-09** `480d9714a7a5` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/fastvm-org/apis/fastvm-api/changes/v1/builds/post.md)

---

[API](https://skmtc.dev/fastvm-org/apis/fastvm-api.md) · [All operations](https://skmtc.dev/fastvm-org/apis/fastvm-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/fastvm-org/fastvm-api/revisions/480d9714a7a5/schema)
