Dependencies & Ordering (After/Wants/Requires)
Why Dependencies and Ordering Break Production
Most systemd problems are not “systemd is weird”. They are dependency modeling mistakes: services start in the wrong order, start before requirements are ready, or create circular dependencies. In production, your service should boot predictably every time.
Ordering vs Readiness: The #1 Misunderstanding
After= controls start order, not readiness. If you write:
After=network.target
It means: “start after systemd starts networking units”, not “the network is usable”. Your DNS might still be down, routes not ready, or network not online. This is why apps sometimes fail only on boot.
The Key Directives (Production Meaning)
After= and Before= (Ordering Only)
These specify ordering. They do not pull units in, and they do not guarantee readiness.
After=postgresql.service
Means: if both units are started, order them. It does not mean postgresql will start automatically unless you also add Wants/Requires.
Wants= (Soft Dependency)
Wants= pulls another unit in, but if it fails, your unit may still start. Good for optional dependencies.
Wants=network-online.target After=network-online.target
Requires= (Hard Dependency)
Requires= says: if this dependency fails to start, my unit should fail too. Use for truly required services (database, critical mount).
Requires=postgresql.service After=postgresql.service
Production rule: do not overuse Requires=. It increases boot fragility. Use it only when your service cannot function without the dependency.
BindsTo= (Tight Coupling)
BindsTo ties lifecycles strongly: if the dependency stops, your unit stops. Useful for mounts or devices, but dangerous if used carelessly.
PartOf= (Grouped Restarts/Stops)
PartOf helps propagate restarts/stops for operational grouping. Example: if you restart nginx, restart your app too.
PartOf=nginx.service
network.target vs network-online.target
network.target roughly means “network management is started”. network-online.target means “network is configured and considered online”. But it depends on your network manager and wait-online service.
Production pattern for network-dependent services:
Wants=network-online.target After=network-online.target
Important: ensure the relevant wait-online service exists and is enabled:
- systemd-networkd-wait-online.service
- NetworkManager-wait-online.service
Readiness: Use Health Checks and Retries, Not Wishful Ordering
Even if ordering is correct, readiness may not be. DNS might fail, DB might be starting, migrations may be running. Production-safe approach:
- Application should retry dependencies (DB, cache) with backoff
- systemd can do simple restart-on-failure loops with backoff
- Use explicit readiness probes (HTTP health checks) at higher layers
Common Dependency Patterns
Service Depends on Database (Typical)
[Unit] Requires=postgresql.service After=postgresql.service
But also: your app should still retry DB connection on boot. Do not rely solely on ordering.
Service Needs a Mount
If your app needs /srv mounted:
[Unit] RequiresMountsFor=/srv/myapp
This is often safer than manual After=mount units.
Avoiding Circular Dependencies
Circular dependencies cause boot deadlocks or unpredictable ordering. Symptoms:
- Units stuck in activating
- Jobs canceled due to ordering cycle
Debug with:
systemd-analyze critical-chain systemctl list-dependencies myapp journalctl -b -u myapp --no-pager
Use systemd-analyze to See Real Boot Order
systemd-analyze blame | head -n 30 systemd-analyze critical-chain
This shows which units delay boot and which dependencies are in the chain.
Operational Reality: Don’t Make Boot Fragile
A production server must recover after reboot without humans. Over-modeling dependencies makes boot fragile. Prefer:
- Minimal hard dependencies
- Retries and backoff in application
- Clear observability (logs show why dependency failed)
Common Production Mistakes
- Assuming After= means “ready”
- Using Requires= for optional components
- Creating circular dependencies via PartOf/BindsTo misuse
- Not enabling wait-online service but using network-online.target
- Building boot success on perfect dependency timing (no retries)
Mental Model
systemd dependencies are about ordering and lifecycle. Readiness is a separate concept. Production robustness comes from: ordering where necessary + retries where reality is messy.
Production Checklist
- Use After= for ordering only (do not confuse with readiness)
- Use Wants= for soft dependencies, Requires= only for truly hard needs
- For network: Wants+After network-online.target (and ensure wait-online exists)
- Use RequiresMountsFor for filesystem needs
- Run systemd-analyze critical-chain when boot behavior is weird
- Ensure the app has retry/backoff for dependency readiness