Skip to content

Linux

systemd Type=simple versus Type=forking

08/11/2026 · 2 min read · Tanveer Ahmed

Applies to Linux This applies to any Linux distribution running systemd; the unit syntax and systemctl commands are the same everywhere.

The most common systemd unit fault is a mismatch between the Type setting and how the program actually behaves. The symptoms are strange enough to send people looking in the wrong place entirely.

Type=simple

systemd starts the command and treats that process as the service. The process must stay in the foreground. If it forks and the parent exits, systemd sees the main process exit and concludes the service stopped.

With Restart=always, it starts it again. And again. The result is a service that reports itself active while restarting continuously, spawning a new instance every few seconds.

Type=forking

For programs that daemonise: the parent forks a child and exits. systemd waits for the parent to exit and considers the service started. Because the process it launched is gone, it needs PIDFile= to know which process is really the service.

[Service]
Type=forking
PIDFile=/run/myservice.pid
ExecStart=/usr/bin/myservice

Spotting the mismatch

systemctl show myservice -p NRestarts --value    # climbing = restart loop
systemctl show myservice -p MainPID --value      # 0 or wrong = tracking lost
journalctl -u myservice | grep -i 'scheduled restart'

A restart counter that climbs while the service appears to work is the signature of Type=simple on a daemonising program.

The modern preference

Where the program supports it, run it in the foreground with Type=simple or Type=notify. Daemonising was a workaround for init systems that could not supervise processes. systemd can, so the fork serves no purpose and removes systemd’s ability to track the service accurately.

Many daemons have a --foreground or -D flag for exactly this.

Restart policy

Restart=on-failure is almost always the right choice. Restart=always restarts a service that exits cleanly on its own, or one you end with a plain kill rather than systemctl stop, which is rarely wanted and turns a configuration error into a loop that hides the original failure.

Related reading