The Party Invitation Analogy
One of systemd's most important capabilities is managing dependencies — knowing that a web application needs its database running before it starts, and that the database needs the network available before it starts. Without this, services start in random order and fail unpredictably.
Three directives control this: Wants=, Requires=, and After=. Understanding the difference between them is critical.
Wants= — Weak Dependency
Think of inviting a casual friend to your party. You want them there, and you'll try to make it happen, but if they can't make it, the party continues without them.
In systemd: if Unit A has Wants=B, systemd will attempt to start B when starting A. If B fails to start, A starts anyway. Use this for optional dependencies — things that enhance the service but aren't required for basic operation.
Requires= — Strong Dependency
Think of inviting the guest of honor. If they don't show up, there's no party.
In systemd: if Unit A has Requires=B, systemd will attempt to start B when starting A. If B fails to start, A fails immediately. Use this for hard dependencies — things without which the service cannot function at all.
After= — Ordering (Not Requirement)
This is the most commonly misunderstood directive. After= does not cause B to start. It only says: "if both A and B are going to start, start B first and wait for it to be active before starting A."
Without After=, systemd might start A and B simultaneously (parallel startup). If A tries to connect to B before B is ready, A fails — even if both units eventually would have started successfully.
The correct pattern for a hard dependency with ordering combines both directives in the [Unit] section: Requires=postgresql.service alongside After=postgresql.service. This says: "PostgreSQL must start successfully (Requires), and I must start after it is active (After)."
BindsTo= — Even Stronger Than Requires
There is a fourth directive worth knowing: BindsTo=. Like Requires=, it fails A if B fails to start. But it goes further: if B stops while A is running, A is also stopped immediately. Use this when A is meaningless without B running continuously — for example, a network namespace service that must stop if the underlying network interface disappears.