Publishing a Docker image from CI should be repeatable and multi-architecture. This generator produces a GitHub Actions workflow that configures Docker Buildx, logs into Docker Hub or GHCR, builds with layer caching, and pushes tags derived automatically from your Git context.
Who uses this and when
The most common scenarios: you have a Node.js API, a Python FastAPI service, or a Go binary, and you want every push to main to publish a fresh image automatically. Teams shipping to Kubernetes, Railway, Render, or any container-based platform rely on this exact pattern so they never have to build and push manually again.
How it works
The workflow chains five official Docker actions in sequence:
docker/setup-qemu-actionenables cross-architecture emulation so a standardubuntu-latestrunner can build ARM images without ARM hardware.docker/setup-buildx-actionprovisions the Buildx builder, which is required for multi-platform support and for thecache-to/cache-fromlayer cache options.docker/login-actionauthenticates to the chosen registry. For GHCR this works with the built-inGITHUB_TOKEN; for Docker Hub you must addDOCKERHUB_USERNAMEand aDOCKERHUB_TOKENaccess token as repository secrets.docker/metadata-actioncomputes tags and OCI labels automatically from Git context — branch name, semver from tags likev1.2.3, and the short commit SHA — so each push produces traceable images with no hand-written tag logic.docker/build-push-actionbuilds for your selected platforms, reads the layer cache, pushes the image, and writes the updated cache back.
Worked example
For a project at myorg/api-service, selecting Docker Hub, platforms linux/amd64,linux/arm64, and caching on, a push to main would produce tags like:
myorg/api-service:main
myorg/api-service:main-abc1234
A push of the Git tag v2.1.0 would additionally produce:
myorg/api-service:2.1.0
myorg/api-service:2.1
myorg/api-service:2
myorg/api-service:latest
The metadata action handles all of that — you write zero tag logic yourself.
Practical guidance
- Secrets: add
DOCKERHUB_USERNAMEandDOCKERHUB_TOKEN(use an access token, not your password) in your repo’s Settings → Secrets → Actions. GHCR only needsGITHUB_TOKEN, which is automatically available. - Multi-platform trade-off: building both
linux/amd64andlinux/arm64typically doubles build time because QEMU emulates the ARM CPU. If you only deploy toamd64hosts, omitlinux/arm64for faster runs. - Layer caching:
cache-type=ghastores BuildKit layer exports in the GitHub Actions cache (10 GB cap per repo). If your Dockerfile has stable base layers at the top, only the changed application layers rebuild on subsequent pushes — often saving 60–80% of build time. - First run vs. subsequent runs: the first push after enabling caching will be slow (cold cache). Every run after that benefits from the restored layers.
- Triggering on specific paths: use
on: push: paths: ['Dockerfile', 'src/**']to skip the build when only docs change.
Tips and notes
- For GHCR, the workflow can use the built-in
GITHUB_TOKEN; for Docker Hub you must addDOCKERHUB_USERNAMEand aDOCKERHUB_TOKENaccess token. - Multi-platform builds are slower but produce a single tag that runs on both Intel and ARM hosts.
- Layer caching via
type=ghamakes incremental builds fast; cold builds still pay full cost. - The metadata action’s semver tags only appear when you push a Git tag like
v1.2.3. - This generator outputs YAML only — no images are built or pushed by this tool.