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.
| Capability | podman build and buildah | docker buildx build |
|---|---|---|
| Rootless execution | Rootless and daemonless by default (podman README) | Client talks to a BuildKit instance, usually behind a daemon |
| Cache backends | Registry 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 format | OCI v1 by default, --format docker for schema 2 manifests (buildah build manual) | OCI or Docker manifest, selectable per exporter |
| Remote builders | No BuildKit client, so builds stay on the runner | --driver remote over TLS (Docker builders documentation) |
| Job containers and services | Runner 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.
| Placement | Label or profile | Per minute |
|---|---|---|
| podman build on the runner | warp-ubuntu-latest-x64-2x, 2 vCPU, 8 GB | $0.004 |
| podman build on the runner | warp-ubuntu-latest-x64-4x, 4 vCPU, 16 GB | $0.008 |
| podman build on the runner | warp-ubuntu-latest-x64-8x, 8 vCPU, 32 GB | $0.016 |
| podman build on the runner | warp-ubuntu-latest-arm64-4x, 4 vCPU, 16 GB | $0.006 |
| Remote builder session | 16 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.
Related Questions
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.