Dependencies & Ordering
systemd in Depth
Chapter 4 · Dependencies & Ordering
systemd1-3 used After=network.target without fully explaining it. This chapter is the real depth — and the single most common point of confusion anyone new to systemd runs into.
Two Genuinely Separate Axes — What vs. When
The core confusion this chapter exists to resolve: "dependency" (should this unit even be started) and "ordering" (when, relative to another unit, should it start) are two separate, independently configured axes in systemd — not one combined concept, however natural that assumption feels at first. Wants=/Requires= control whether another unit gets started at all, as a side effect of this one starting. After=/Before= control only the order, with zero effect on whether anything actually gets started.
Wants= vs. Requires= — How Strict Is the Dependency?
Wants= is a soft dependency — if the wanted unit fails to start, the wanting unit still proceeds normally. The more common, more resilient choice for most real-world dependencies. Requires= is a hard dependency — if the required unit fails, systemd treats this unit's own startup as a failure too, and can stop it if the required unit later stops. Genuinely stricter, appropriate only when a unit truly cannot function at all without the other one.
A concrete example: a web server might Wants= a caching service — nice to have, but the site can still serve requests, just more slowly, if the cache is down — while it Requires= its own database, since it genuinely cannot function at all without one.
After= vs. Before= — Ordering Only, No Dependency Implied
This directly resolves systemd1-3's own After=network.target: it only says "if network.target is going to start anyway, for whatever reason, start after it." It does not, by itself, cause network.target to be started as a side effect. A unit with only After= and no Wants=/Requires= for the same target could, in principle, start with no network at all, if nothing else on the system independently wanted networking. This is exactly why real unit files commonly pair both together.
A Concrete Worked Example
In the second, broken version, if nothing else on the system happens to Want= network-online.target independently, this unit could start immediately — network or no network — with no error, no warning, just silently wrong behavior on a system where networking happens to come up slowly or not at all.
Target Units as Synchronization Points
systemd1-1 previewed target units replacing runlevels; systemd1-5 covers them in full. A target unit doesn't "do" anything itself — it's purely a named synchronization point, a milestone other units can Want=/Require=/order themselves around. This lets many otherwise-unrelated units all agree on "wait until networking is genuinely usable" without each one needing its own bespoke detection logic.
Viewing the Real Dependency Tree
Shows the actual, resolved dependency tree for a real unit on a real system — a genuinely concrete way to see this chapter's abstract material in practice, rather than only reasoning about it on paper.
| Controls | Affects whether the other unit starts? | |
|---|---|---|
| Wants= / Requires= | Whether the other unit gets started at all | Yes — that's the entire point |
| After= / Before= | Ordering only, relative to another unit | No — purely sequencing |
systemctl list-dependencies --reverse NAME shows the opposite direction — everything that depends on this unit. Genuinely useful for answering "what would actually break if I disabled this," before doing it.
After= when a unit genuinely needs both ordering and an actual guarantee the other unit starts — or, less commonly, writing only Wants=/Requires= and assuming the "right" start order comes for free. Neither assumption holds; the two axes are independent, and most real dependencies need both lines, deliberately.
Hands-On Exercises
A logging service should only run if a remote log-collector service is available, and must not start until after it. Write the two [Unit] lines needed to correctly express this.
📄 View solutionExplain the real difference between using Wants= and Requires= for a service's own database dependency, including what happens to the service in each case if the database fails to start.
📄 View solutionA unit has only After=postgresql.service in its [Unit] section, with no Wants= or Requires=. Explain a real scenario in which this unit could start successfully even though PostgreSQL never started at all.
📄 View solutionChapter 4 Quick Reference
- Wants=/Requires= control whether another unit starts; After=/Before= control only ordering — two genuinely separate axes
- Wants= — soft dependency, proceeds even if the wanted unit fails; Requires= — hard dependency, failure propagates
- After= alone never guarantees the other unit is started — pairing Wants=/Requires= with After= is the real, common pattern
- Target units are pure synchronization points — they don't "do" anything, just let unrelated units agree on a shared milestone
systemctl list-dependencies NAME/--reverse NAME— see the real, resolved dependency tree in both directions- The classic mistake: only After=, expecting it to also guarantee the other unit starts — it doesn't