Can I Use Podman Instead of Docker in GitHub Actions?

Yes, on Linux runners, for building and running OCI images. The tradeoff is that Buildx cache backends and remote builders stay Docker-side features.

Yes, Podman builds and runs OCI images on Linux GitHub Actions runners, it is already present on the Ubuntu runner images, and swapping docker build for podman build in a workflow is a change to the run steps rather than to the job. The tradeoff is narrow and worth naming up front: the Buildx cache backends and remote builders are BuildKit client features, so a podman-only workflow keeps its layer cache in a registry and keeps the build on the runner.

Answer

Podman covers the part of a Docker workflow that most GitHub Actions jobs actually use: build an image from a Dockerfile, tag it, log in to a registry, push it. Podman runs rootless and without a daemon, so no privileged socket has to exist on the runner for a build to work (containers/podman README). Podman is preinstalled on the Ubuntu runner images: the Ubuntu 24.04 x64 image lists Podman 4.9.3, Buildah 1.33.7, and Skopeo 1.13.3 (actions/runner-images), and the ARM64 partner image lists Podman and associated container tools (actions/partner-runner-images). WarpBuild Ubuntu runners carry the same tooling as the GitHub-hosted images (preinstalled software documentation), so the labels in the cloud runners documentation run a podman build with no install step.

Here is where the two toolchains match and where they diverge, for the parts a GitHub Actions job depends on.

Capabilitypodman build and buildahdocker buildx build
Rootless executionRootless and daemonless by default (podman README)Client talks to a BuildKit instance, usually behind a daemon
Cache backendsRegistry repositories only, through --cache-from and --cache-to (buildah build manual)inline, registry, local, gha, s3, azblob (BuildKit README)
Local layer reuse--layers caches intermediate images on the runner disk, which dies with the job (buildah build manual)BuildKit local cache in the builder's state directory
Multi-platform--platform repeated or comma separated, with --manifest instead of --tag; cross-architecture RUN needs qemu-user-static (buildah build manual)--platform with QEMU or with native builder nodes
Image formatOCI v1 by default, --format docker for schema 2 manifests (buildah build manual)OCI or Docker manifest, selectable per exporter
Remote buildersNo BuildKit client, so builds stay on the runner--driver remote over TLS (Docker builders documentation)
Job containers and servicesRunner drives these through the Docker API (GitHub workflow syntax)Supported directly

A working podman build and push job, with the registry login step that most workflows get from a login action:

name: image

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: warp-ubuntu-latest-x64-4x
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Log in to the registry
        run: |
          echo "${{ secrets.GITHUB_TOKEN }}" | podman login ghcr.io \
            --username "${{ github.actor }}" \
            --password-stdin

      - name: Build
        run: |
          podman build \
            --layers \
            --format docker \
            --cache-from ghcr.io/${{ github.repository }}/buildcache \
            --cache-to ghcr.io/${{ github.repository }}/buildcache \
            --tag ghcr.io/${{ github.repository }}:${{ github.sha }} \
            .

      - name: Push
        run: podman push ghcr.io/${{ github.repository }}:${{ github.sha }}

--format docker is there for registries and downstream tools that expect schema 2 manifests; drop it if OCI v1 is fine everywhere the image lands. The same three steps exist as actions if you prefer that shape: redhat-actions/podman-login, redhat-actions/buildah-build, and redhat-actions/push-to-registry.

Detail

The cache is what you are trading

Buildah accepts one cache shape: --cache-from names repositories to pull cache images from, and --cache-to names repositories to push newly built cache images to (buildah build manual). BuildKit accepts six exporters, including gha against the GitHub Actions cache, s3, and azblob (BuildKit README). Leaving Buildx behind means every cache read and write becomes a registry round trip on a fresh runner, and the cache is only as fresh as the last successful push.

Two practical consequences follow. First, cache correctness now depends on registry retention and tag hygiene, so a cache repository that gets pruned quietly turns every build into a full rebuild. Second, cache transfer time scales with image layer size rather than with what changed, because the runner has no local layer store to fall back on. A private registry in the same region as the runner is the usual mitigation.

The alternative is to leave the build where a warm cache already lives. Remote Docker builders run on dedicated builder virtual machines that keep the layer cache on local disk across jobs, and the runner attaches to one through a buildx remote driver over TLS (Docker builders documentation). That path is Docker-side by construction. Teams that want the cache behavior and are not tied to podman for policy reasons move the build there instead, which the Docker builds solution page walks through end to end.

Multi-platform images

Podman builds multi-architecture images without Buildx. Pass --platform more than once or as a comma separated list, and use --manifest in place of --tag so the result is a manifest list. Cross-architecture RUN instructions need emulation software on the host from packages like qemu-user-static, and building on the native architecture is the documented preference (buildah build manual). On GitHub Actions that argues for a matrix with one native job per architecture, pushing by digest, then a small job that merges the digests with podman manifest. Both legs of that matrix run on native hardware from the cloud runners documentation.

Where podman does not substitute

Job containers, service containers, and Docker container actions are driven by the runner itself. GitHub documents that workflows using them require a Linux runner, and that a self-hosted Linux runner must have Docker installed (GitHub workflow syntax). Podman can expose a Docker-compatible API socket through podman system service and point clients at it with DOCKER_HOST (podman-system-service manual), which is a setup task on the image rather than a flag in your workflow.

macOS is the other boundary. macOS runners do not support nested virtualization and cannot run Docker (cloud runners documentation), and podman on macOS runs containers inside a Linux virtual machine of its own (podman-machine manual), so container image builds belong on the Linux labels either way.

What each placement costs

Rates below come from the cloud runners documentation and the Docker builders documentation, checked on 2026-08-13.

PlacementLabel or profilePer minute
podman build on the runnerwarp-ubuntu-latest-x64-2x, 2 vCPU, 8 GB$0.004
podman build on the runnerwarp-ubuntu-latest-x64-4x, 4 vCPU, 16 GB$0.008
podman build on the runnerwarp-ubuntu-latest-x64-8x, 8 vCPU, 32 GB$0.016
podman build on the runnerwarp-ubuntu-latest-arm64-4x, 4 vCPU, 16 GB$0.006
Remote builder session16 vCPU, 32 GB, 100GB disk$0.06

Worked model, holding the minute count equal so the rate is the only variable. A repository builds 400 images a month at 8 minutes each, which is 3,200 minutes.

  • podman on warp-ubuntu-latest-x64-4x: 3,200 x $0.008 = $25.60 per month, plus registry pulls and pushes for the cache repository on every build.
  • Remote builder session on the 16 vCPU profile: 3,200 x $0.06 = $192.00 per month in builder session minutes, on top of the runner minutes the job still consumes, with the layer cache held on the builder disk.

Minute counts do not stay equal in practice once a warm layer cache is involved, and that side of the arithmetic lives on the Docker builds solution page.

Is Podman already installed on GitHub Actions runners?

On Ubuntu images, yes. The Ubuntu 24.04 x64 image lists Podman 4.9.3, Buildah 1.33.7, and Skopeo 1.13.3 (actions/runner-images), and the ARM64 partner image lists Podman and associated container tools. WarpBuild Ubuntu runners carry the same tooling as the GitHub-hosted images, so podman build works with no install step.

Can Podman use a remote Docker builder?

No. A remote builder is attached through a buildx remote driver over TLS (Docker builders documentation), which is a BuildKit client feature, and podman has no BuildKit client. A podman-only workflow builds on the runner and keeps its cache in a registry. The profiles and their rates are in the remote Docker builder catalog.

Do job containers and service containers work with Podman?

Not on their own. GitHub documents that Docker container actions, job containers, and service containers require a Linux runner with Docker installed (GitHub workflow syntax). Podman can serve a compatible API socket with podman system service and DOCKER_HOST (podman-system-service manual), which is extra setup on the runner image.

What replaces docker/build-push-action in a Podman workflow?

A podman login step plus podman build and podman push, or redhat-actions/buildah-build with redhat-actions/push-to-registry if you want the same step shape. Both routes take --cache-from and --cache-to against a registry repository, which is the only cache backend Buildah supports. For how layer caching works underneath either tool, see what BuildKit is.

Pick the labels for your build jobs from the cloud runners documentation, price the minutes on the pricing page, and compare the runner-side build with a warm builder cache on the Docker builds solution page.

Start with $10 in free credits

Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.