LinuxVII · systemd and Service ManagementTransactions
Targets, dependencies, and ordering
What you'll learn
- Trace the start order systemd computes on boot
- Distinguish Requires, Wants, Requisite, and BindsTo
- Understand the difference between After/Before and the dependency types
- Diagnose "why is my service starting before X" issues
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
systemd does not start services one at a time. On every state
change — boot, runlevel change, manual systemctl start — it
computes a transaction: a list of jobs that bring the system to
the desired state.
How systemd computes the transaction
flowchart LR
STATE["Current state"]
TARGET["Desired state"]
GRAPH["Dependency graph"]
TX["Transaction<br/>(ordered jobs)"]
APPLY["Apply jobs"]
STATE --> GRAPH
TARGET --> GRAPH
GRAPH --> TX
TX --> APPLY
For each unit, systemd asks:
- Is this unit supposed to be active in the desired state?
- Is it currently active?
- Does the dependency graph allow activation?
If yes to 1 and 3 and no to 2, the unit is queued for start. If yes to 1 but the dependency graph says a required unit is inactive, the start is deferred until the dependency is active.
Requires, Wants, Requisite, BindsTo
| Directive | On start | On stop |
|---|---|---|
Requires= | Start together; if dependency fails, this unit fails | Stop together |
Wants= | Soft preference; ignore failure of dependency | (no effect) |
Requisite= | Like Requires, but dependency must already be active when this unit starts | (no effect) |
BindsTo= | Like Requires, but stronger — if dependency is stopped, this unit is also stopped | Always stopped together |
PartOf= | (no effect on start) | When the LISTED unit is stopped or restarted, this unit is stopped/restarted too. One-way: changes to this unit do not affect the listed unit |
$ grep -E '^(Requires|Wants|Requisite|BindsTo|PartOf)' /usr/lib/systemd/system/nginx.service /usr/lib/systemd/system/sshd.service 2>/dev/null/usr/lib/systemd/system/sshd.service:Wants=network-online.target
/usr/lib/systemd/system/sshd.service:After=network-online.targetIllustrative output
After and Before — ordering, not dependency
After= and Before= are NOT dependencies. They are ordering
constraints: “this unit starts AFTER the named unit”, or “this
unit starts BEFORE the named unit”. The named unit is not pulled
in if it is not already wanted by something else.
[Unit]
After=network-online.target
Wants=network-online.target
This pair is common: “after” for ordering, “wants” to pull in the dependency. Either alone is incomplete:
After=alone: ordering only — if network-online.target is not already going to start, sshd may start before the network.Wants=alone: dependency without ordering — sshd may race the network.
Reading the actual order
$ systemd-analyze dot sshd.service 2>/dev/null | head -20; systemd-analyzeBootup finished in 4.234s (kernel) + 12.345s (userspace) = 16.579s
graphical.target reached after 12.001s in userspaceIllustrative output
Conflicts
Conflicts= means two units cannot be active at the same time.
Starting one stops the other. Used for exclusive resources:
[Unit]
Conflicts=umount.target
Conflicts produces interesting behaviour: if unit A is running
and you systemctl start B, systemd stops A and starts B. Useful
when services claim exclusive resources (a network interface, a
serial port).
Targets
Targets group units for collective state changes. Boot into
multi-user.target means “every unit that multi-user.target
Wants or Requires must be active”. Targets themselves do nothing
— they are just collection points.
$ systemctl list-dependencies multi-user.target | headmulti-user.target
● ├─accounts-daemon.service
● ├─chrony.service
● ├─cron.service
● ├─dbus.service
● ├─getty.target
● ├─nginx.service
● ├─sshd.service
● └─systemd-update-utmp.service
...Illustrative output
Common dependency bugs
- My service starts before its dependency: missing
After=. - My service starts but the dependency does not: missing
Wants=orRequires=. - My service refuses to start: required dependency is in failed state; fix the dependency first.
- Cycle detected: two units depend on each other. systemd refuses to start either until the cycle is broken.
$ systemctl status myapp 2>&1 | head -10● myapp.service - MyApp daemon
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: disabled)
Active: failed (Result: start-limit-hit) since ...
Main PID: 12345 (code=exited, status=2)
...Illustrative output
Knowledge check
Knowledge check · 3 questions
Q1. What is the difference between `Requires=` and `Wants=`?
Q2. A unit with only After=postgresql.service will start without postgresql.service if nothing else pulled that unit into the transaction.
Q3. Which of the following are correct dependency declarations? Select all that apply.
Passing score: 75%. Answers are checked in this browser.