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.
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:
- The key changes (instruction text, ENV/WORKDIR/USER context, or COPY’d file contents differ).
- The cached commit id no longer exists server-side — the builder falls through to real execution and prints a
cache entry stalenote.
--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
- vers commit — snapshot a live VM instead
- vers run-commit — boot a built commit
- vers tag — name a commit for humans