Skip to content
Latchkey

How to Publish a Docker Image to GHCR With GitHub Actions

Log in to ghcr.io with the built-in token and push with docker/build-push-action, tagging the image from docker/metadata-action.

Grant packages: write, log in to ghcr.io with GITHUB_TOKEN, generate tags with docker/metadata-action, then build and push with docker/build-push-action. No personal token is needed for same-repo packages.

Steps

  • Add permissions: packages: write and contents: read.
  • Log in to ghcr.io using docker/login-action with GITHUB_TOKEN.
  • Compute tags with docker/metadata-action.
  • Build and push with docker/build-push-action.

Workflow

.github/workflows/publish.yml
permissions:
  contents: read
  packages: write
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
      - uses: docker/build-push-action@v6
        with:
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Common pitfalls

  • Without packages: write the push fails with "denied: permission_denied".
  • A new package is private by default; link it to the repo and set visibility, or pulls 404 for others.
  • The image name must be lowercase; github.repository with an uppercase owner breaks the push, so lowercase it.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →