CLI guide

August 8, 2026 · View on GitHub

Build a Dockerfile into a microsandbox-runnable image, step by step. Nothing here needs Docker, a daemon, or root.

1. Install the CLI

The -g is what puts the beambox command on your PATH:

bun add -g @beamhop/beambox   # or: npm i -g @beamhop/beambox
beambox version

To try it once without installing anything, replace beambox with bunx @beamhop/beambox (or npx @beamhop/beambox) in every command below.

You also want the microsandbox runtime, which is what executes RUN steps and what msb run comes from:

msb --version

If your Dockerfile has no RUN instruction, skip that: a declarative build never boots a VM and never loads the microsandbox SDK.

2. Write a Dockerfile

Nothing beambox-specific — an ordinary Dockerfile in an ordinary build context:

FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

3. Build it

beambox build -t my-app:local .

The positional argument is the build context; ./Dockerfile inside it is the default file. Progress goes to stderr, so piping stdout stays clean.

  pulling docker.io/library/node:22-slim
  [1/6] WORKDIR /app
  [2/6] COPY package.json package-lock.json ./
  [3/6] RUN npm ci --omit=dev
        added 84 packages in 3s
  ...
✓ built 4 layers in 11.2s
  loaded my-app:local

With no output flag beambox loads the image into the local microsandbox cache — the useful default, because it is the thing msb can immediately run.

4. Run it

msb run my-app:local

5. Send it somewhere else

Each output flag is independent, and they combine — one build, several destinations:

beambox build -t my-app:local -o app.tar .                    # docker save archive
beambox build -t my-app:local -o app.oci.tar --format oci .   # OCI Image Layout archive
beambox build -t my-app:local --layout ./out/oci .            # unpacked, for skopeo/crane
beambox build -t ghcr.io/me/my-app:v1 --push .                # any OCI Distribution v2 registry
beambox build -t my-app:local -o app.tar --load .             # archive *and* the msb cache

msb load and docker load both accept either archive format. --push needs a --tag naming where to push, and pushes the first tag.

Registry credentials already in ~/.docker/config.json are used automatically. For a plain-HTTP local registry, add --insecure.

6. The flags you will actually reach for

FlagWhat it does
-f, --file <path>A Dockerfile outside the context, or under another name
-t, --tag <ref>Tag the result; repeatable
--target <stage>Stop at a named stage — build the builder stage and no further
--build-arg K=VSet an ARG; repeatable. Bare --build-arg K forwards K from the environment
--platform linux/arm64Target platform. Declarative builds only — see the limit below
--no-cacheIgnore cached RUN results
--insecurePlain HTTP for registries
-q, --quietErrors only

beambox help prints the full list.

7. Multi-stage, and stopping early

FROM node:22 AS builder
WORKDIR /src
COPY . .
RUN --mount=type=cache,target=/root/.npm npm ci && npm run build

FROM node:22-slim
COPY --from=builder /src/dist /app
WORKDIR /app
CMD ["node", "index.js"]
beambox build -t app:local .                    # the final stage
beambox build --target builder -t build:local . # stop at the first

The cache mount becomes a microsandbox named volume: the npm cache survives between builds, and because it is its own filesystem nothing in it lands in the image.

8. In CI

- run: npx @beamhop/beambox build -t ghcr.io/me/app:${{ github.sha }} --push .
  env:
    # Or pre-write ~/.docker/config.json; beambox reads it.
    REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}

A build with no RUN step needs no runtime at all, so it works on any stock runner. A build with RUN steps needs microsandbox installed on the runner.

9. When it fails

beambox fails loudly rather than producing an image that looks right and behaves wrong.

MessageWhat to do
UnsupportedInstructionError: ONBUILD (line 12)Rewrite the Dockerfile — refusals are deliberate, not gaps to work around
RunFailedError: exit 1The command itself failed; the step's output is above the error
NoExecutorErrorA RUN step with no microsandbox runtime — install msb, or drop the RUN
PlatformMismatchError--platform asked for a non-host architecture and the build has a RUN step
CopySourceErrorA COPY source matched nothing — check the path and .dockerignore
DockerfileParseErrorSyntax error, with the line and column

Refused by name and line number, never silently skipped: ONBUILD, MAINTAINER, ADD from a URL, RUN --mount=type=secret|ssh, RUN --network, RUN --security, and non-default BuildKit frontends.

Next

  • Generate images from code instead of a Dockerfile — the library guide
  • Teach a coding agent to do all of this — the agent guide