Skip to main content
Where Publish to npm ships libraries, publishing to Docker ships images: the packages under packages/ and modules under modules/ that carry a Dockerfile and run as containers. Deploy an API walks through building the app module’s image by hand with docker build/docker push; docker:publish automates that across the workspace — save a registry token once, then let one command log in, build each target that has a Dockerfile, tag it, and push it to Docker Hub.

What gets published

Every directory under packages/ and modules/ is a candidate, but only those that ship a Dockerfile are built — the rest are reported as ignored. The image is tagged <username>/<name>:<tag>, where <name> is the directory name and <username> comes from your saved credentials.
SourceLocationBuilt when
Packagespackages/<name>/packages/<name>/Dockerfile exists.
Modulesmodules/<name>/modules/<name>/Dockerfile exists.
The build context is the target directory and the image is built from its Dockerfile (docker build .). Make sure that Dockerfile and its .dockerignore reference paths relative to that directory — see Deploy an API for the app module’s multi-stage example.

Step 1 — Save a Docker token

Publishing authenticates with a Docker access token. Save it once with docker:credentials:create; the registry, username, and token are written as block-style YAML to ~/.talos/credentials/docker.yml under the default profile and reused by every publish.
talos docker:credentials:create
You are prompted for the registry (defaults to docker.io), username, and token (input hidden), or pass them non-interactively for CI:
talos docker:credentials:create --registry=docker.io --username=ooneex --token=dckr_pat_xxxxxxxx --silent
Create the token at app.docker.com → Personal access tokens. Give it Read & Write scope so it can push images, and the shortest expiry your release cadence allows.
The token is stored in plaintext under ~/.talos/credentials/. Keep that directory off shared machines and out of any backup that leaves your control. In CI, inject the token via --token from a secret store rather than committing docker.yml.

Step 2 — Publish

With credentials saved, build and push every container in the workspace:
talos docker:publish
Or target specific packages and modules by name (comma-separated):
talos docker:publish --packages=gateway,worker
talos docker:publish --modules=billing,catalog
By default the tag is the target’s package.json version, falling back to latest. Override it explicitly:
talos docker:publish --modules=billing --tag=edge

Options

OptionDescriptionDefault
--packagesComma-separated package names to publish (under packages/).All packages and modules
--modulesComma-separated module names to publish (under modules/).All packages and modules
--tagImage tag to build and push.package.json version, else latest
--silentSuppress log output and the publishing spinner (use in CI).false

What the command does

docker:publish runs once up front, then per target:
  1. Logs in to the registry with docker login, feeding the saved token through stdin so it never appears in the process arguments. A failed login aborts the whole run.
  2. For each resolved target that ships a Dockerfile, builds the image with docker build -t <username>/<name>:<tag> . from the target directory.
  3. Pushes it with docker push. A build failure skips the push for that target and is reported.
  4. Skips targets with no Dockerfile — discovered targets are silently counted as ignored; an explicitly named target without one is reported as an error.
At the end it prints a summary — N published, M ignored.
For any registry other than docker.io, the image reference is prefixed with the registry host (for example ghcr.io/ooneex/gateway:1.2.0), so the same command targets Docker Hub or a private registry depending on the registry you saved in Step 1.

Publish from CI

The same commands run unattended. Provide the token from a secret and add --silent to keep logs clean:
.github/workflows/docker.yml
name: docker
on:
  push:
    tags: ["*@*"]        # matches release:create tags, e.g. @talosjs/gateway@1.2.0
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: >
          bunx talos docker:credentials:create
          --registry=docker.io --username="$DOCKER_USERNAME"
          --token="$DOCKER_TOKEN" --silent
        env:
          DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
          DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
      - run: bunx talos docker:publish --silent
The CI runner needs a working Docker daemon (available on GitHub’s ubuntu-latest). Give the token Read & Write scope on only the repositories you push, and prefer a short expiry.

Checklist

  • Save the Docker token once with docker:credentials:create (or inject it via --token in CI).
  • Add a Dockerfile to each package/module you want containerized — targets without one are skipped.
  • Let the tag default to the package.json version, or pass --tag for a named tag such as edge.
  • Ensure docker is on PATH and the daemon is running before publishing.
  • In CI, add --silent and pull the token from a secret store — never commit docker.yml.