Podman Instead of Docker: What Actually Changes
21 Sep 2026Podman runs containers without a background daemon and without root by default. Most docker commands work unchanged if you alias docker to podman. The gaps show up in Compose support, networking defaults, and anything that assumes a single daemon socket.
The core difference
Docker runs a daemon (dockerd) as root, and the docker CLI talks to it over a socket. Every container is a child of that daemon. If the daemon crashes or restarts, your containers can be affected even if nothing else changed.
Podman has no daemon. Each podman run forks a process directly, and that process is the container — a normal child process of your shell, run by your user if you’re rootless. There’s nothing central to crash, and nothing running as root unless you explicitly ask for it.
What’s compatible
The CLI surface is close enough that this works for most people:
alias docker=podman
podman run, podman build, podman ps, podman exec — same flags, same output shape, same behavior for the common cases. Podman also speaks the same image format (OCI) and can pull from the same registries.
Where it actually diverges
Compose. Docker Compose talks to the Docker daemon’s API. Podman doesn’t have that daemon, so docker-compose doesn’t work against it out of the box. You need podman-compose (a separate, less mature reimplementation) or Podman’s own podman play kube for pod-based multi-container setups. If your team leans hard on a docker-compose.yml with build contexts, healthchecks, and depends_on ordering, expect some behavior differences.
Networking. Docker containers get a bridge network and predictable inter-container DNS by default. Podman’s rootless networking uses slirp4netns or pasta for the network namespace, which is slower and has different port-forwarding behavior — rootless containers can’t bind to ports below 1024 without extra setup, same as any other non-root process.
Systemd integration. Podman generates systemd unit files for containers (podman generate systemd, or the newer Quadlet), so a container can run as a real systemd service — restarts, dependency ordering, and logs all go through systemd instead of a container-specific supervisor. Docker doesn’t have an equivalent; you’d normally reach for restart: always and hope, or wrap it yourself.
Root containers that need it. Some workloads (things that bind low ports as root, or need specific kernel capabilities Docker’s daemon setup papers over) behave differently rootless. You can still run Podman as root (sudo podman) to sidestep this, which gives up the main security benefit.
Comparison
| Docker | Podman | |
|---|---|---|
| Daemon | Yes, runs as root | None |
| Rootless by default | No (needs separate setup) | Yes |
| Compose | Native | Needs podman-compose or play kube |
| Systemd units | Manual | Built in (generate systemd, Quadlet) |
| CLI compatibility | — | ~95% drop-in |
The failure mode to expect
If you migrate a project with a nontrivial docker-compose.yml, test it fully before switching your team over. Things like named volumes with specific driver options, custom bridge networks with static IPs, or depends_on with condition: service_healthy are the first things to break under podman-compose. Run both side by side for a week rather than cutting over in one step.
Verdict
New project, solo VPS, no complex Compose file: Podman is the safer default — rootless containers mean a container escape doesn’t hand over root on the host. Existing team already deep in Docker Compose with healthchecks and multi-service dependencies: stay on Docker until you’ve tested the Compose replacement thoroughly, the daemon-less architecture doesn’t buy you enough to justify breaking a working setup.