Units and state
Dependencies and targets
Read requirement and ordering relationships without assuming that After also starts another unit.
8 minute lesson
systemd separates whether a unit is required from when it should start. This distinction prevents many confusing unit files, and misreading it causes many broken ones.
Requirement vs ordering
Requires= and Wants= express requirement relationships. Wants= is the soft version: start that other unit too, but carry on if it fails. Requires= is hard: if the required unit fails to start, this unit fails with it. Prefer Wants= unless the service genuinely cannot exist without the dependency.
After= and Before= express ordering only. After=postgresql.service means “if both of us are starting, let PostgreSQL go first”. It does not pull PostgreSQL in.
That leads to the classic bug: a unit with After=network-online.target but no Wants=. Nothing asked the target to be reached, so the ordering is meaningless. The two directives travel in pairs:
[Unit]
Description=Demo API server
Wants=network-online.target
After=network-online.target postgresql.service
This unit pulls in network-online.target, waits for it, and orders itself after PostgreSQL without demanding it exists.
Targets group units
A target is a unit with no process of its own. It exists to group other units around a boot or operational state. multi-user.target is the normal server boot state; when you write WantedBy=multi-user.target in an [Install] section, enabling the service creates a symlink in that target’s .wants/ directory.
Read the graph
You can walk relationships in both directions:
systemctl list-dependencies --reverse network-online.target
network-online.target
● ├─demo-api.service
● └─nginx.service
The --reverse flag answers “who depends on this” instead of “what does this depend on”.
To see ordering as systemd resolved it, query the unit’s effective properties:
systemctl show demo-api.service -p Wants -p After
Run the list-dependencies command on your server. Find one unit that wants the target, then confirm one ordering relationship in that unit’s effective configuration. If you find an After= with no matching Wants= or Requires=, you have found a latent bug.
Lesson completed