CertGrid CertGrid
Concepts·Podman

Podman Quadlet and Deprecated systemd Generation

`podman generate systemd` still runs and opens with `[DEPRECATED]`. It writes a static 35-line unit with the whole `podman run` command inside it; Quadlet reads a nine-line file and regenerates the unit on every reload.

systemd and Quadlet Guide 25 of 47 Intermediate

Written against the versions above. Podman follows the distribution here rather than a vendor repository, so the version you get is the one Ubuntu shipped. The commands are stable across 5.x.

Every command on this page ran on podman01.
Server NameIP AddressOSRolesCPURAMHDD
PODMAN01192.168.0.24Ubuntu 26.04 LTSPrimary Container Host2 Core4 GB50 GB

Before you start

  1. The command tells you itself

    It has not been removed, and asking for help is the fastest way to learn its status:

    [DEPRECATED] Generate systemd units
    ...
    DEPRECATED command:
    It is recommended to use Quadlets for running containers and pods under
    systemd.

    Worth knowing because you will meet it in existing documentation, blog posts and older runbooks - most of the material written about running Podman under systemd predates Quadlet, and it all uses this command.

    bash Example session
    podman generate systemd --help[DEPRECATED] Generate systemd units Description:  Generate systemd units for a pod or container.  The generated units can later be controlled via systemctl(1). DEPRECATED command:It is recommended to use Quadlets for running containers and pods under systemd. Please refer to podman-systemd.unit(5) for details.

    Expected resultA [DEPRECATED] banner and a recommendation to use Quadlet.

    Success conditionYou can recognise advice that is out of date from the command it uses.

  2. What it produces

    Run it against a container with --files --new and it writes container-legacy.service into the current directory - a complete, static unit you then copy into ~/.config/systemd/user/ and enable yourself.

    Look at what is inside it:

    ExecStart=/usr/bin/podman run \
    	--cidfile=%t/%n.ctr-id \
    	--cgroups=no-conmon \
    	--rm \
    	--sdnotify=conmon \
    	--replace \
    	-d \
    	--name legacy docker.io/library/nginx:alpine

    The container's entire definition is a shell command embedded in a unit file, and the image tag is on the last line of it. Also a --cidfile and three %t/%n expansions, because without Quadlet's Type=notify wiring the unit has to track the container ID itself.

    The header says autogenerated by Podman, which is the trap: it was generated once, and from that moment it is a hand-maintained file. Nothing regenerates it when the container it came from changes.

    bash Example session
    podman generate systemd --name legacy --files --new DEPRECATED command:It is recommended to use Quadlets for running containers and pods under systemd. Please refer to podman-systemd.unit(5) for details./home/sysadmin/container-legacy.servicecat container-legacy.service# container-legacy.service# autogenerated by Podman 5.7.0# Sat Aug 22 11:51:54 UTC 2026 [Unit]Description=Podman container-legacy.serviceDocumentation=man:podman-generate-systemd(1)Wants=network-online.targetAfter=network-online.targetRequiresMountsFor=%t/containers [Service]Environment=PODMAN_SYSTEMD_UNIT=%nRestart=on-failureTimeoutStopSec=70ExecStart=/usr/bin/podman run \	--cidfile=%t/%n.ctr-id \	--cgroups=no-conmon \	--rm \	--sdnotify=conmon \	--replace \	-d \	--name legacy docker.io/library/nginx:alpineExecStop=/usr/bin/podman stop \	--ignore -t 10 \	--cidfile=%t/%n.ctr-idExecStopPost=/usr/bin/podman rm \	-f \	--ignore -t 10 \	--cidfile=%t/%n.ctr-idType=notifyNotifyAccess=all [Install]WantedBy=default.target

    Expected resultA written filename, then a 35-line unit with a multi-line podman run inside ExecStart.

    Success conditionYou have read a generated unit and can find the image tag in it.

  3. Why the replacement is better, concretely

    Put the two side by side for one ordinary task - change the image tag:

    | | generate systemd | Quadlet | |---|---|---| | what you edit | ExecStart, mid-command, in a generated file | Image=, one line | | after editing | daemon-reload, restart | daemon-reload, restart | | regeneration | none - the file is now yours | every reload | | lives in | ~/.config/systemd/user/ | ~/.config/containers/systemd/ | | enablement | systemctl enable | [Install] in the source file | | volumes, networks | flags in the command | Volume=, Network= keys | | auto-update | not supported | AutoUpdate=registry |

    The difference that matters is the third row. A generated unit is a snapshot; a Quadlet file is a source. Once you have edited a generated unit it has no relationship to the container it was made from, and the usual failure is regenerating it later and silently losing your changes.

    Migrating is mostly mechanical: read the flags out of ExecStart and write them as [Container] keys - -p becomes PublishPort=, -v becomes Volume=, -e becomes Environment=, --name becomes ContainerName=. Keep your [Service] and [Unit] sections as they are; Quadlet passes both through untouched, which is visible in the generated output in guide 40.

    One thing genuinely lost: generate systemd could produce a unit for a container that already existed, which made it a quick way to capture something you built interactively. Quadlet has no equivalent - you write the file. In practice podman inspect gives you everything you need to write it.

    bash Example session
    rm -f container-legacy.servicepodman rm -f legacylegacy

    Expected resultThe generated file and its container removed.

    Success conditionYou can convert an ExecStart line into [Container] keys.

Troubleshooting

Official sources