Build Images
A deployment runs container images. Toa builds them from the Context: one per composition, and one per extension service that no composition runs. You write no Dockerfile; you say where the images go and, when a component needs something special, what to add to the build.
§Where images go
The Context toa create wrote has a placeholder under registry.
Put your registry there:
# context.toa.yaml
registry:
base: registry.example.com/store base is prepended to every image name. The core composition of store becomes registry.example.com/store/store/composition-core. registry: registry.example.com/store is
shorthand for the same.
docker must be logged in to the registry before toa push or toa deploy.
The registry usually differs per environment:
registry:
base@local: localhost:5000
base@production: registry.example.com/store §Building
$ npx toa build # build on the local Docker daemon
$ npx toa push production # build and push
$ npx toa deploy production # build, push and deploy toa push and toa deploy skip an image the registry already has. Deploying sources that were
already pushed builds nothing.
To see what would be built without building it:
$ npx toa export images ./images # Dockerfiles and sources, as files
$ npx toa export tags production # the image reference of every workload To run the image of a composition on your machine, see toa compose --dock.
§Tags
An image’s tag is eight hexadecimal digits that follow from what the image was built from.
- The tag changes when a member component changes, and not otherwise. A release that touches one component produces a new image for one composition.
- The tag carries no environment. The same sources deployed to staging and production are one image, built once. What was tested is what is released.
toa deploy production also moves a second tag, <image>:production, onto the image it
deployed, so the registry shows what each environment runs. toa push writes only the first
kind.
Beside each image the repository holds a deps-<tag> image with the components’ npm
dependencies. It is rebuilt only when dependencies, the base image or the build options change,
so a deploy that changes code alone is quick.
Do not name an environment eight hexadecimal digits, or deps- and eight: nothing that
cleans the registry could tell such an environment tag from a build’s.
§What goes into an image
- Each component’s dependencies are installed from its own
package.json, in its own directory. Dependencies of the repository root are not in the image. - Pin git dependencies to a commit. A dependency named by a moving ref, such as a branch, is installed once and not refreshed until something else changes the dependencies.
- Sources are copied as files. A directory linked into a component with a symbolic link is copied as what it points to, so components can share source through links. A link the build cannot read fails the build.
- Heavy optional packages are installed only where a component needs them. A composition
whose components declare a storage with the
s3provider gets the AWS SDK; others do not. Your workspace needs the same packages to run locally;toa npminstalls them.
§Platforms
registry:
platforms: [linux/amd64, linux/arm64] What the images are built for. Without the key, they are built for linux/amd64, linux/arm/v7 and linux/arm64.
platforms: ~ builds only for the machine that builds. It is faster, and it is what a local
registry usually wants:
registry:
platforms: [linux/amd64]
platforms@local: ~ Building for fewer platforms is the simplest way to shorten a build.
§Private registries
registry:
credentials: registry-credentials credentials is the name of a Kubernetes secret holding registry credentials, in the form
Kubernetes uses for pulling images. The pods use it as their image pull secret.
Toa does not create this secret. Create it in the namespace yourself; a deploy that does not find it there is refused with the other missing secrets.
§The base image
Every image is built from ghcr.io/toa-io/runtime:<version>, which is published with each Toa
release and has the runtime installed. The version is runtime.version of the Context, or the
version of the CLI that builds when the Context does not say:
runtime:
version: 1.0.0 §Your own base image
Name another base for the whole Context:
registry:
build:
image: node:24.22.1-alpine3.24
run: |
npm i --prefix /toa @toa.io/runtime --omit=dev
ln -s /toa/node_modules/.bin/toa /usr/local/bin/toa A base image must provide the toa binary. The stock image has it; one of your own has to
install it, as the run lines above do. Install the runtime into /toa.
A single component can ask for a base of its own, in its manifest:
# components/pictures/manifest.toa.yaml
build:
image: node:24.22.1-bookworm-slim All components of a composition are built into one image. If they ask for different bases, the
composition has to choose with its image key, or the build is
refused.
§Adding build steps
pictures needs ffmpeg in its image. run adds commands to the build, one RUN instruction per line:
registry:
build:
run: |
apk add --no-cache ffmpeg
apk add --no-cache imagemagick A component can add its own:
# components/pictures/manifest.toa.yaml
build:
run: apk add --no-cache vips Both are applied, the Context’s first. Use the Context’s for what every image needs and the component’s for what one component needs.
§Build arguments
arguments passes environment variables of the building machine into the build:
registry:
build:
arguments: [NPM_TOKEN]
run: npm config set //npm.example.com/:_authToken ${NPM_TOKEN} $ NPM_TOKEN=... npx toa deploy production Each named variable is available to the run commands and to the dependency install.
A build argument stays in the image. It is readable by anyone who can pull the image and by every container that runs it. Pass only tokens you can afford to expose that way, scoped to reading packages.
§A private npm registry
runtime:
registry: https://npm.example.com
proxy: http://proxy.example.com:3128 Every image build installs from this registry, through this proxy. Both are optional and independent.
§Extension service images
The gateway and the other extension services need images too. registry.services says where
they come from:
registry:
services: published | Value | Meaning |
|---|---|
build | Build one image per service into registry.base. The default. |
published | Use the images Toa publishes; build nothing. |
published is faster and is the usual choice:
ghcr.io/toa-io/extension-exposition-gateway:<version>
ghcr.io/toa-io/extension-introspection-explorer:<version>
ghcr.io/toa-io/extension-configuration-values:<version> Before choosing:
- Published images are pulled from
ghcr.io, not from your registry. They are public, andregistry.credentialsdoes not apply to them. A cluster that cannot reachghcr.ioneedsbuild. buildneeds@toa.io/runtimeinstalled on the machine that builds, beside@toa.io/operations.publisheddoes not.- With
build, every Toa upgrade rebuilds every service image. - A service that a composition runs is part of that composition’s image. Neither setting applies to it.
The setting can differ per environment:
registry:
services: published
services@local: build §Staying on a supported release
Toa’s published images of old prereleases are removed: a prerelease older than 90 days that is not among the last 30 is deleted, with its service images. Stable releases stay.
An application pinned to a removed prerelease cannot pull published service images and cannot
rebuild on that runtime’s base image. Images already in your own registry keep running. Upgrade
regularly, or pin a stable release.
§Cleaning your registry
Every deploy of changed sources adds images. Nothing removes them for you. When you set up retention in your registry, keep:
- every image an environment tag (
:production,:staging) currently points at; - the last few build tags, which are what you can roll back to;
- the
deps-images those depend on.
How far back you can roll is exactly what retention leaves.
§Every registry key
| Key | Default | Meaning |
|---|---|---|
base | required | registry and path prefix for images |
platforms | linux/amd64, linux/arm/v7, linux/arm64 | platforms to build for; ~ for the builder’s own |
credentials | none | name of the image pull secret |
services | build | build or published |
build.image | the Toa runtime image | base image |
build.run | none | extra build commands, one per line |
build.arguments | none | environment variables passed to the build |
And of runtime: version, registry, proxy. In a component’s manifest: build.image and build.run.