Pushing Containers To GitHub Packages

In my previous blog, you read about building containers with GitHub Actions and pushing them to Docker Hub. In this post, I’ll extend the workflow to push the containers to the GitHub Packages registry.

Why Use GitHub Packages

GitHub Packages is a software package hosting service, similar to npmjs.org, rubygems.org, or hub.docker.com. It allows you to host your packages and code in one place, privately or publicly, and use them as dependencies in your projects.

GitHub uses the README file in your repository to generate a description and details about the package or installation process. For each package version, GitHub adds metadata, including links to the author, repository, commit SHA, version tags, and date.

So Why Use GitHub Packages Over Docker Hub?

  • If you use GitHub to store your Dockerfile in git, then it makes sense to use GitHub Packages, as it allows you to have everything in one place.
  • If you use GitHub Actions for CI/CD, you can leverage Packages in your workflows.
  • If you use other package formats, like npm or rubygems, you can use the same technology to store the packages.

Changing the GitHub Action Workflow

You have to be authenticated to push to a Docker repository. In the current workflow, we have a step called Docker Registry, which looks like this

- name: Docker Registry
  run: docker login -u $DOCKER_USERNAME -p $DOCKER_ACCESS_TOKEN

If no server is specified, the default setting for the Docker application is to return the value defined by the daemon. Thus, we have to update the above code example to the following:

- name: Docker Registry

We then set this new environment variable at the env block and provide it with the correct server.

DOCKER_REGISTRY: docker.pkg.github.com

As the values for DOCKER_USERNAME and DOCKER_ACCESS_TOKEN are different for GitHub Packages, we also need to update the repository secrets with the new values.

Update the repository secrets

The tagging needs to follow the following pattern docker.pkg.github.com/owner/repository/image_name:version. Note that this is different from the pattern we currently use. We should change the run step of the Building Docker Image build, as follows.

- name: Building Docker Image
  run: |
    # Change all uppercase to lowercase
    REPOSITORY=$(echo $GITHUB_REPOSITORY | tr '[A-Z]' '[a-z]')  

    docker build --build-arg HUGO_VERSION=$HUGO_VERSION --no-cache \
    -t $DOCKER_REGISTRY/$REPOSITORY/hugo-docker:latest .

Here, we remove the $DOCKER_USERNAME and start to use the $GITHUB_REPOSITORY variable, which GitHub provides as a default. It contains the owner and repository name — in our case, PaulusTM/hugo-docker. The uppercase characters are a problem for Docker, so we need to transform them to lowercase.

The last change is the Docker push step. We need to remove $DOCKER_USERNAME here as well and use the same lowercase transformation for the $GITHUB_REPOSITORY variable.

- name: Push Docker Container to Registry
  run: |
    # Change all uppercase to lowercase
    GITHUB_REPOSITORY=$(echo $GITHUB_REPOSITORY | tr '[A-Z]' '[a-z]')

    docker push $DOCKER_REGISTRY/$GITHUB_REPOSITORY/hugo-docker

If we push these changes to the repo and wait until the workflow is complete, you’ll see that we now have one package included within the repository.

Find the new package

You can host multiple packages in the same repository. You can also build several versions of the same container and have them all available next to your codebase.

The packages are also visible on your profile page so people can find all packages that are published in one simple overview.

Packages on your profile

Package Details

The images hosted on GitHub include details and download statistics, along with their entire history, reference command to pull the image, and instructions for using it as a base image in a Dockerfile.

Update the repository secrets

Keep in mind that you can’t delete packages that you push to registry. GitHub restricts this action so that you don’t break projects that depend on your package.


If you want to use GitHub Webhook to trigger a follow-up build, then you can use RegistryPackageEvent. This could be useful if you are using tools like Jenkins or Kubernetes and want to trigger a new deployment every time your package is published in GitHub Packages.

My Thoughts on GitHub Packages

I hope that after reading this, you’ll try out Github Packages for yourself. It is easy to get started, and it provides a nice overview of available packages for your project so new users can find the packages easily