Pushing to Docker Hub from GitHub Actions

A common workflow consists of using GitHub Actions to build a Docker image and then push it to Docker Hub.

See also the post on pushing to Docker Hub from GitLab CI.

Docker Image

We’re not concerned about the Docker image itself, so let’s keep that simple. Our Dockerfile simply inherits from the mysql base image.

FROM mysql:8.2.0


Okay, now we need to set things up so that the image will build and push automatically to Docker Hub each time that we push a new commit on the master branch. Create a .github/workflows/build.yml that looks like this:

name: Build & Push Docker Image
      - "master"

    runs-on: ubuntu-latest
    - uses: actions/checkout@v4
    - uses: docker/setup-buildx-action@v3
    - uses: docker/login-action@v3
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_PASSWORD }}
    - uses: docker/build-push-action@v5
        context: .
        push: true
        tags: >
          ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:${{ github.sha }},
          ${{ secrets.DOCKERHUB_USERNAME }}/${{ github.event.repository.name }}:latest          

There are a few important steps in the pipeline:

  1. actions/checkout — Checkout the repository.
  2. docker/setup-buildx-action — Set up the Docker Buildx environment.
  3. docker/login-action — Login to Docker Hub. You need to provide a username and password, which I’m accessing from repository secrets.
  4. docker/build-push-action — This does the heavy lifting: building the image and pushing to Docker Hub. Setting up tags correctly is important. I’m tagging the latest image with both latest and the commit SHA.
A test repository on Docker Hub showing a few tagged images.

You can either hard-code the name of the image or use the repository name. I’m adopting the latter approach and getting the repository name via ${{ github.event.repository.name }}.

You will probably want to generate an unique tag for each build. In the YAML above I’ve used the commit SHA via ${{ github.sha }}. Another option might be ${{ github.run_number }}.


Q. How do I deal with a insufficient_scope: authorization failed error?
A. Check that your username is used in the image tag. For example, the tag should be something like datawookie/test and not just test.