Skip to main content
  1. Posts/
  2. Podman/

Quadlet and Podlet in Podman: How to Stop Writing Long podman run Commands and Run Containers Under systemd

··1448 words·7 mins· loading · loading · ·
Stilicho2011
Author
Stilicho2011
Writing about homelab, self-hosting, automation and open-source solutions
Table of Contents
Podman - This article is part of a series.
Part : This Article

Quadlet and Podlet in Podman
#

Containers without Kubernetes and Docker Compose
#

If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).

When I first switched from Docker Compose to Podman, I had a bit of confusion in my head between two very similarly-sounding terms - Quadlet and Podlet. They sound almost identical, both are related to containers, both come up in the same context - and for a while, I’ll admit, I mixed them up. The actual difference is fundamental: Quadlet is Podman’s built-in format for describing containers via systemd, while Podlet is a separate utility that helps generate those descriptions rather than writing them by hand from scratch. In this article I’ll go through both tools in detail, show configuration examples, and compare this approach with the familiar Docker Compose.


1. Quadlet
#

What Quadlet is
#

Quadlet is a mechanism built into Podman that lets you declaratively describe containers, pods, networks, volumes, and images using ordinary systemd unit files of a special format. On system startup, systemd itself translates these files into full-fledged .service units and runs them through Podman - nothing needs to be generated by hand, a daemon-reload is enough.

Quadlet emerged as an evolution of the podman generate systemd idea, except instead of the imperative “generate a unit from an already-running container,” here it’s the opposite - you declaratively describe the desired state, and systemd brings the system to that state itself, including after a host reboot.

Types of Quadlet files
#

ExtensionWhat it describes
.containera single container
.poda pod - a group of containers sharing a network
.volumea named volume
.networka network
.imagean image that needs to be pulled in advance
.buildbuilding an image from a Containerfile
.kubedeployment from a Kubernetes YAML (podman kube play)
.artifactan OCI artifact

Where Quadlet files live
#

  • /etc/containers/systemd/ - system (root) units;
  • ~/.config/containers/systemd/ - user, rootless units.

Example .container file
#

[Container]
Image=docker.io/library/nginx:latest
ContainerName=nginx
PublishPort=8080:80
Volume=nginx-data:/usr/share/nginx/html:Z

[Service]
Restart=always

[Install]
WantedBy=multi-user.target

Example .pod file
#

If you need to group several containers into one pod with a shared network, there’s a separate unit type for that, .pod:

# web-pod.pod
[Pod]
PublishPort=8080:80

The containers themselves then connect to this pod via a reference to the .pod file:

# web-app.container
[Container]
Image=myapp:latest
Pod=web-pod.pod

[Service]
Restart=always
# web-cache.container
[Container]
Image=docker.io/library/redis:latest
Pod=web-pod.pod

[Service]
Restart=always

All containers attached to the same pod share a common network namespace and see each other via localhost - exactly as if the pod had been created manually with podman pod create.

Managing Quadlet units
#

systemctl daemon-reload
systemctl enable --now nginx.container
systemctl status nginx.container
journalctl -u nginx.container -f

From this point on, the container is a full systemd service: autostart at boot via [Install], dependency management via After=/Requires=, unified logging via journalctl, standard Restart= instead of homegrown wrapper scripts.

Advantages of Quadlet
#

  • native systemd integration - no workarounds or homegrown wrapper scripts;
  • autostart and crash recovery through standard systemd mechanisms;
  • dependency management between services (for example, “start after the network is up”);
  • unified centralized logging via journalctl;
  • full support for rootless mode.

Limitations of Quadlet
#

  • requires systemd - doesn’t work on systems without it (some embedded distros, part of the Alpine ecosystem);
  • designed for a single host - no clustering whatsoever;
  • doesn’t replace Kubernetes if you genuinely need autoscaling, multi-node service discovery, and HA.

2. Podlet
#

What Podlet is
#

Podlet is a separate utility written in Rust, not part of Podman itself, but used closely alongside it. Podlet’s job is simple and useful: save you from having to write Quadlet sections by hand when you already have a working podman run/docker run command or a docker-compose.yml file.

Important: Podlet does not create containers and isn’t a runtime - it only generates the text of a ready-made Quadlet file, which then needs to be saved to the right directory and picked up via systemctl daemon-reload.

Generating from a command
#

The simplest scenario - take an existing run command and just replace podman run/docker run with podlet podman run:

podlet podman run -d -p 8080:80 -v nginx-data:/usr/share/nginx/html:Z --name nginx nginx:latest

The output is a ready-made .container file with all the required [Container], [Service], [Install] sections, which you just need to save to ~/.config/containers/systemd/ or /etc/containers/systemd/.

Generating from docker-compose.yml
#

This is probably the most practically useful mode during a migration from Docker Compose:

podlet compose docker-compose.yml

Podlet parses the file and, depending on the project structure, either creates a separate .container file for each service or groups related services into a single .pod together with the accompanying .container files - so that the result matches the original compose project’s architecture as closely as possible.

Generating from an already-running object
#

If a container, pod, network, or volume is already created manually and running, Podlet can “lift” the Quadlet configuration off of it:

podlet generate container nginx

Handy if you first quickly spun something up with a terminal command to check whether it works, then decided to formalize the result declaratively.

Why Podlet is useful in practice
#

  • significantly simplifies migration from Docker and Docker Compose - no need to manually learn the syntax of all the Quadlet sections;
  • reduces the number of mistakes made when writing unit files by hand (a forgotten [Install], an incorrect Volume= section, and the like);
  • speeds up the migration process itself - for a typical project, Podlet’s output usually just needs a bit of tweaking rather than being written from scratch.

3. Quadlet and Podlet together
#

The easiest way to remember the difference: Quadlet is the format that gets executed, and Podlet is the tool that writes it for you. They don’t compete with or replace each other - they’re different layers of the same process.

Docker Compose / podman run
     Podlet   ← generates Quadlet files
    Quadlet   ← declarative format
     systemd  ← turns Quadlet into .service units and starts them
     Podman   ← actually runs the containers/pods

In practice, a typical workflow looks like this: take an existing docker-compose.yml, run it through podlet compose, get a set of .container/.pod files, drop them into ~/.config/containers/systemd/, run daemon-reload - and from that point on everything lives as ordinary systemd services.


4. Comparison with Docker Compose
#

CriterionDocker ComposeQuadlet (+ Podlet)
Requires a daemonYesNo
RootlessLimitedBy default
Autostart on system bootVia workarounds (restart: always + a third-party init)Native, via systemd [Install]
systemd integrationNoneFull
Centralized logsVia docker compose logsVia journalctl, alongside all the system’s other services
Configuration formatYAML (docker-compose.yml)INI-like systemd units
Single hostYesYes

It’s worth understanding separately: Quadlet isn’t a one-to-one replacement for Docker Compose, but rather a different approach to the same result - instead of one YAML file parsed by a separate tool (docker compose/podman-compose), you get a set of systemd units that the operating system itself recognizes. For those already used to managing services via systemctl, this feels more natural than keeping a parallel layer of compose-file orchestration in the system.


5. Practical scenarios
#

Homelab. Nextcloud, media servers (Jellyfin, Plex), reverse proxies (Traefik, Caddy, nginx), monitoring (Prometheus, Grafana) - a typical set of self-hosted services that live perfectly well as Quadlet units and survive a host reboot without extra scripts.

VPS / dedicated server. Web applications, private APIs, CI/CD runners - anywhere a single reliable host is needed without the cost of maintaining a cluster.

Edge / IoT. Minimal resource usage, rootless mode by default, and simple maintenance are especially valuable on weak hardware.


6. When Quadlet isn’t the right tool
#

If you need:

  • horizontal autoscaling under load;

  • an HA cluster across multiple physical nodes;

  • multi-region deployment with load distribution across data centers,

  • then you’ve already outgrown single-host workloads, and you need full-fledged Kubernetes. Quadlet handles single-node infrastructure needs perfectly well, but deliberately doesn’t try to compete with cluster-level orchestration.


7. Summary
#

  • Quadlet - a declarative format that turns Podman containers, pods, networks, and volumes into ordinary systemd services.
  • Podlet - a tool that generates Quadlet files from podman run, docker-compose.yml, or already-running objects, saving time on writing the syntax by hand.
  • Together they provide a secure, minimalist single-node platform with no daemon and no Kubernetes - more than enough for most self-hosted scenarios.

Docker Compose - familiar. Podman - secure. Quadlet - declarative and systemd-native. Podlet - saves time during migration. Kubernetes - when a single host is no longer enough. The choice of a specific tool should be driven by the actual task, not by fashion.


Useful links:

Podman - This article is part of a series.
Part : This Article

Related