Linux Administration·6 min read·

systemd Targets and Boot Order: What Actually Happens at Boot

Follow the dependency chain from sysinit.target through multi-user to graphical, and finally understand what determines boot order on a modern server.

NB

Netbay Developer Relations

Netbay Engineering

On this page

When your server boots, systemd does not execute scripts in a fixed order. It reads every unit on the system, builds a dependency graph, and starts as many units in parallel as that graph allows, synchronizing only where dependencies demand it. Understanding the four targets that anchor the graph explains why your database starts after the filesystem, why a badly written unit can stall boot, and what default.target actually points at.

Targets Are Synchronization Points

A target is a unit that does nothing itself. It exists so other units can be started after it or wanted by it, which makes it the tool for saying: by the time this target is reached, all of these things are ready. Services do not join a target by being listed somewhere; they get pulled in by Wants= and WantedBy= links, which is precisely what systemctl enable creates. Because targets are ordinary units too, you can inspect them with list-dependencies, order against them with After=, and mask them like anything else.

Beyond the boot chain, a handful of special targets matter in practice. rescue.target and emergency.target provide minimal shells for repair work, with emergency being the stricter of the two. reboot.target, poweroff.target, and halt.target wrap the shutdown paths, and shutdown.target acts as the reverse of sysinit.target — a synchronization point for stopping everything cleanly.

The Chain That Matters

Nearly every boot walks the same backbone.

The boot backbone: each target waits for the previous one sysinit.target mounts, swap, udev, journald basic.target sockets, timers multi-user.target your enabled services graphical + display mgr default.target symlink chosen at boot on servers: usually multi-user

sysinit.target covers the machinery everything needs: local filesystem mounts, swap, udev, and the journal. basic.target covers the next layer of plumbing, including sockets and timers. multi-user.target is the real milestone on a server — everything you enabled with WantedBy=multi-user.target starts around it. graphical.target adds a display manager on systems that have one, and on headless machines it behaves as a simple alias. The target the machine actually boots into is whatever default.target points to.

bash
systemctl get-default
systemctl set-default multi-user.target
systemctl list-dependencies multi-user.target --plain

That third command is the honest answer to what happens at boot: the full transitive closure of units pulled in by a target, in one tree.

Wants, Requires, and the network-online Trap

At boot scale, the ordering rules from unit files matter more, and one trap catches nearly everyone: After=network-online.target only does something if network-online.target is actually reached in a meaningful way. On many distros nothing waits for real connectivity unless a wait service is enabled, such as systemd-networkd-wait-online.service, so a unit declaring After=network-online.target may still start with no usable network. Verify on your own distribution rather than assuming.

Equally common: Requires= without After= means start this too, with no ordering guarantee at all — rarely what the author intended. The safe default pairing is Wants= plus After=.

Measuring and Steering Boots

bash
systemd-analyze blame
systemd-analyze critical-chain multi-user.target
sudo systemctl isolate rescue.target
sudo systemctl isolate multi-user.target

blame ranks units by the time they took to start, while critical-chain shows the dependency path that actually determined when the target was reached — the difference between them is where parallelism is hiding your real bottleneck. isolate switches the running system into a target immediately, stopping everything the new target does not require; rescue.target drops you to a single-user shell, the modern replacement for booting into single-user mode.

You can also steer a one-off boot without touching the default: append systemd.unit=rescue.target or systemd.unit=multi-user.target to the kernel command line from the bootloader, and the machine boots straight into that target, this boot only. It is the cleanest way to recover a server whose normal target is broken, and it leaves default.target untouched for the next boot.

Takeaway: boot order is a graph, targets are its milestones, and default.target is just a symlink with opinions. list-dependencies and critical-chain turn boot mysteries into readable diagrams.

Practice this on a server you can reboot freely — Netbay VPS instances come up in under 60 seconds at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance