Skip to main content
vers build parses a literal Dockerfile, runs each instruction against a throwaway VM, and commits a “layer” after every step. The output is a commit id — same as vers commit — so it plugs straight into the rest of the primitives: vers run-commit, vers branch, vers tag.

Synopsis

PATH is the build context directory; its default is .. The Dockerfile defaults to <PATH>/Dockerfile and can be overridden with -f.

Description

Every Dockerfile instruction maps to a Vers action: After each RUN/COPY, the builder calls vm.Commit and stores the resulting commit id in .vers/buildcache.json, keyed by sha256(parent_commit ‖ normalized_instruction ‖ content_hash_for_COPY). On a hit, the step is skipped and the cached commit becomes the new parent — the same shape as Docker’s layer cache, just using Vers commits as layers.

Options

FROM semantics

FROM scratch always requires --mem-size, --vcpu-count, and --fs-size-vm-mib. There are no implicit defaults — the build will fail fast if you forget them.

Supported instructions

FROM, RUN, COPY, ADD (local paths only), ENV, ARG, WORKDIR, USER, LABEL, CMD, ENTRYPOINT, EXPOSE. Line continuations, exec-form arrays (CMD ["node", "server.js"]), .dockerignore, and $VAR / ${VAR} substitution are all supported.
Not yet supported — parsed but rejected at execution time:
  • Multi-stage builds (FROM ... AS name, COPY --from=stage)
  • ADD from URLs or with tar auto-extraction
  • HEALTHCHECK, SHELL, VOLUME, STOPSIGNAL, ONBUILD

Examples

Build from a tagged base

Build from scratch with explicit sizing

Compose with other commands

JSON output for scripting

Caching

The cache lives at .vers/buildcache.json inside your project. Keys are deterministic: the same Dockerfile, same build args, same file contents produce the same key. Two scenarios trigger a re-execution:
  1. The key changes (instruction text, ENV/WORKDIR/USER context, or COPY’d file contents differ).
  2. The cached commit id no longer exists server-side — the builder falls through to real execution and prints a cache entry stale note.
Use --no-cache to bypass lookup entirely. Use vers commit delete to explicitly remove layers you don’t want.

Common Patterns

Build, tag, boot — one flow

Iterative dev loop

Cache makes rebuilds cheap. Layout your Dockerfile so cheap-to-invalidate things come late (application code) and expensive things come early (system deps, language runtimes):

Pin a known-good commit in CI

Debug a failing step

--keep leaves the builder VM alive so you can SSH in after a failed RUN:

See also