GitHub Actions Docker Build & Publish Workflow

Build and push a Docker image to Docker Hub or GHCR on every push

Generate a GitHub Actions workflow that sets up Docker Buildx, logs into Docker Hub or GitHub Container Registry, builds a multi-platform image with layer caching, and pushes tags derived from branch, semver, and commit SHA. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is the difference between Docker Hub and GHCR?

Docker Hub is Docker's public registry at docker.io and GHCR is GitHub Container Registry at ghcr.io, tied to your GitHub account or org. GHCR can authenticate with the built-in GITHUB_TOKEN, while Docker Hub needs a username and access token stored as secrets.

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:

  1. docker/setup-qemu-action enables cross-architecture emulation so a standard ubuntu-latest runner can build ARM images without ARM hardware.
  2. docker/setup-buildx-action provisions the Buildx builder, which is required for multi-platform support and for the cache-to/cache-from layer cache options.
  3. docker/login-action authenticates to the chosen registry. For GHCR this works with the built-in GITHUB_TOKEN; for Docker Hub you must add DOCKERHUB_USERNAME and a DOCKERHUB_TOKEN access token as repository secrets.
  4. docker/metadata-action computes tags and OCI labels automatically from Git context — branch name, semver from tags like v1.2.3, and the short commit SHA — so each push produces traceable images with no hand-written tag logic.
  5. docker/build-push-action builds 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_USERNAME and DOCKERHUB_TOKEN (use an access token, not your password) in your repo’s Settings → Secrets → Actions. GHCR only needs GITHUB_TOKEN, which is automatically available.
  • Multi-platform trade-off: building both linux/amd64 and linux/arm64 typically doubles build time because QEMU emulates the ARM CPU. If you only deploy to amd64 hosts, omit linux/arm64 for faster runs.
  • Layer caching: cache-type=gha stores 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 add DOCKERHUB_USERNAME and a DOCKERHUB_TOKEN access token.
  • Multi-platform builds are slower but produce a single tag that runs on both Intel and ARM hosts.
  • Layer caching via type=gha makes 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.