RWX Container Image Build Syntax

This is the reference documentation for building images. See the guide on building container images for high-level concepts.

Building images on RWX is substantially faster and more ergonomic than building images with docker build due to techniques detailed in the original proposal.

The syntax for building images on RWX is mostly the same as normal RWX run definitions. Some configuration options are exposed via writing to the $RWX_IMAGE configuration directory from within a task.

FROM

Dockerfile:

FROM ubuntu:24.04

RWX:

base:
  image: ubuntu:24.04
  config: none

You'll almost always want to use config: none when building images. This will start building your image pristinely from the defined image without any additional configuration applied.

RUN

Dockerfile:

RUN \
  apt-get -y update && \
  apt-get -y upgrade && \
  apt-get -y install curl jq && \
  apt-get -y clean

On RWX, run scripts are defined as multi-line shell scripts, so you do not need the && chaining.

tasks:
  - key: system
    run: |
      apt-get -y update
      apt-get -y upgrade
      apt-get -y install curl jq
      apt-get -y clean

COPY and ADD

Rather than using COPY and ADD, you'll mostly use the git/clone package and artifacts. You'll also use filters to avoid needing as many COPY statements as you typically find in docker files.

For example, in a Dockerfile, you usually have a COPY . . towards the end to copy the entire build context into the container. On RWX however, you can start your run definition with cloning your full git repository.

- key: code
  use: system
  call: git/clone 1.8.0
  with:
    repository: https://github.com/rwx-cloud/rwx-image-example.git
    ref: ${{ init.commit-sha }}

After defining a task such as code that contains your full git repository, you can then filter additional commands. So while in a Dockerfile, before copying your full build context into your container, you might do this:

COPY package.json package-lock.json ./
RUN npm ci

On RWX you can do this:

- key: npm-install
  use: code
  run: npm ci
  filter:
    - package.json
    - package-lock.json

Artifacts

You can use artifacts to mimic copying files between layers in multi-stage builds.

Multi-stage build copy example

Here is a full example comparing the docker approach to the RWX approach. This example shows building a Node.js application without copying all of node_modules into the final container.

# ---- Stage 1: Build the app ----
FROM node:24-slim AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ---- Stage 2: Production image ----
FROM node:24-slim AS runtime

WORKDIR /app
# Copy only the build output from the builder stage
COPY --from=builder /app/dist ./dist

# Set environment and command
ENV NODE_ENV=production
CMD ["node", "dist/index.js"]

On RWX:

base:
  image: node:24-slim
  config: none

tasks:
  - key: code
    call: git/clone 1.8.0
    with:
      repository: https://github.com/your-org/your-repo.git
      ref: main

  - key: npm-install
    use: code
    run: npm ci
    filter:
      - package.json
      - package-lock.json

  - key: build
    use: npm-install
    run: npm run build
    outputs:
      artifacts:
        - key: dist
          path: dist

  - key: dist
    run: cp -a ${{ tasks.build.artifacts.dist }}/. ./dist

  - key: image
    use: dist
    run: echo "node dist/index.js" | tee $RWX_IMAGE/command
    env:
      NODE_ENV: production

Note that the dist task in the RWX definition does not have a use dependency, making it the same as the multi-stage build approach.

ARG

On RWX, you use init parameters to configure runtime values.

Dockerfile:

# Define a required build argument (no default)
ARG APP_VERSION

# Use it in a command
RUN echo "Building version: ${APP_VERSION}" > version.txt

RWX:

tasks:
  - key: version-file
    run: echo "Building version: ${APP_VERSION}" > version.txt
    env:
      APP_VERSION: ${{ init.app-version }}

CMD

Dockerfile:

CMD node server.js

On RWX, write the command to $RWX_IMAGE/command

tasks:
  - key: image
    run: echo "node server.js" > $RWX_IMAGE/command

ENTRYPOINT

Dockerfile:

ENTRYPOINT /usr/local/bin/myapp
CMD "--help"

On RWX, write the entrypoint to $RWX_IMAGE/entrypoint

tasks:
  - key: image
    run: |
      echo "/usr/local/bin/myapp" > $RWX_IMAGE/command
      echo "--help" > $RWX_IMAGE/help

ENV

Dockerfile:

ENV PORT=3000

RWX:

tasks:
  - key: image
    run: ...
    env:
      PORT: 3000

ENV

Dockerfile:

SHELL ["/bin/bash", "-c"]

RWX:

tasks:
  - key: image
    run: echo "/bin/bash -c" > $RWX_IMAGE/shell

Note that not all RWX packages have been updated yet to support shells other than bash.

USER

Dockerfile:

USER myuser

RWX:

tasks:
  - key: image
    run: echo "myuser" > $RWX_IMAGE/user

WORKDIR

On RWX, the workdir it currently always /var/mint-workspace

EXPOSE

Docker supports defining exposed ports, such as

EXPOSE 3000

However, EXPOSE is only for documentation purposes. It does not affect which ports can actually be exposed from the image. RWX does not currently support EXPOSE.

Not Supported

The following Dockerfile options are not currently supported on RWX.

HEALTHCHECK	Check a container's health on startup.
LABEL	Add metadata to an image.
MAINTAINER	Specify the author of an image.
ONBUILD	Specify instructions for when the image is used in a build.
STOPSIGNAL	Specify the system call signal for exiting a container.
VOLUME	Create volume mounts.