skip to content

On a systemd host, how does the system decide which target to boot into by default, how do you inspect and change that choice, and how do you override it for a single boot?

level: juniorimportance: should knowfreq 50%

answer

  1. one unit is activated at boot
  2. the default is a symlink
  3. /etc wins over /usr/lib
  4. get-default and set-default
  5. kernel command line for one boot only

basics

~20 s

systemd activates default.target at boot, which is a symlink at /etc/systemd/system/default.target falling back to the one shipped under /usr/lib/systemd/system. Read it with systemctl get-default, change it with systemctl set-default, and override one boot with systemd.unit= on the kernel command line.

solid answer

~40 s

At the end of early boot systemd activates a single unit, `default.target`, and everything else comes up because that target wants or requires it, directly or transitively. `default.target` is not a real unit of its own — it is a symlink. systemd looks for `/etc/systemd/system/default.target` first, which is the local administrator's choice, and falls back to the distribution's symlink under `/usr/lib/systemd/system/default.target`. `systemctl get-default` prints the resolved name, typically `graphical.target` on a desktop and `multi-user.target` on a server, and `systemctl set-default multi-user.target` rewrites the symlink in `/etc`. For a one-off, you don't touch the disk at all: append `systemd.unit=rescue.target` to the kernel command line in the boot loader and that boot uses it instead, leaving the persistent default untouched.

code

bash · 4 lines
bash
systemctl get-default
ls -l /etc/systemd/system/default.target
systemctl set-default multi-user.target
systemctl list-dependencies default.target

go deeper

for a junior

Be able to say that systemd boots one unit, default.target, that it is a symlink, and that systemctl get-default and set-default read and write it. Naming multi-user.target as the usual server choice is expected.

for a middle

Explain the resolution order — /etc/systemd/system first, then the vendor symlink — and distinguish isolate (change the running system now) from set-default (change the next boot). Mention systemd.unit= as the non-persistent override.

for a senior

Show that you use this in recovery: editing the kernel line touches no disk, which matters when the root filesystem is unwritable or the default target itself is what is broken. Explain how you check whether a host actually reached its target.

for a principal

Treat the default target as fleet configuration, not a per-host tweak: it should come from the image or configuration management, and drift between hosts booting to graphical and multi-user is a real cost in memory, attack surface and boot time.

## The single entry point systemd does not have a list of things to start at boot. It has exactly one job: activate `default.target`. Every service that comes up on a healthy host does so because something in the dependency graph rooted at that target pulled it in — a `Wants=`, a `Requires=`, or the `.wants/` symlink that `systemctl enable` created for it. That means "what starts at boot?" always resolves to two sub-questions: which target is the default, and what does that target pull in. ## Resolving default.target `default.target` is a symlink, and systemd resolves it through the normal unit search path, where the administrator directory wins over the vendor directory: ```bash $ systemctl get-default multi-user.target $ ls -l /etc/systemd/system/default.target lrwxrwxrwx 1 root root 41 ... /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target ``` If `/etc/systemd/system/default.target` does not exist, the vendor symlink under `/usr/lib/systemd/system/` is used instead — on a desktop image that usually points at `graphical.target`, on a minimal server image at `multi-user.target`. ## Changing it persistently ```bash systemctl set-default multi-user.target ``` This does exactly one thing: it replaces the symlink in `/etc/systemd/system/`. There is no separate database, and you can achieve the same result with `ln -sf` — `set-default` is the supported spelling and validates that the target exists. On a server that boots to a login manager for no reason, this one command reclaims a surprising amount of memory and boot time. ## Overriding a single boot Editing the kernel command line in the boot loader (`e` at the GRUB menu, then boot without saving) is the recovery path, because it changes nothing on a disk you may not be able to write to: ``` systemd.unit=rescue.target ``` systemd parses `systemd.unit=` from `/proc/cmdline` and activates that unit instead of `default.target`. The legacy shorthands from the SysV era are still recognised too — `single`, and the bare digits — so old runbooks continue to work. You can also see what the running system was told: ```bash cat /proc/cmdline ``` ## Switching targets on a running system `set-default` affects the *next* boot. To change the current one: ```bash systemctl isolate multi-user.target ``` `isolate` starts the named unit and stops everything not required by it, which is a much bigger hammer than `start` — it is how you drop a running graphical host to a text environment without rebooting. It is not persistent; the next boot goes back to whatever the symlink says. Getting these two confused is a common interview stumble: `isolate` is now-and-temporary, `set-default` is later-and-permanent. ## Compatibility aliases Distributions ship `runlevel3.target` and `runlevel5.target` as alias symlinks to `multi-user.target` and `graphical.target` respectively, and the `runlevel` command still prints something plausible. These exist so that decades of scripts and muscle memory keep working; they are a compatibility skin over the target graph, not a second mechanism. ## Verifying what the default actually brings up The target name alone tells you little — what matters is its transitive closure: ```bash systemctl list-dependencies default.target systemctl list-units --type=target --state=active systemctl list-unit-files --state=enabled ``` The first renders the tree that will be pulled in, expanding sub-targets; the second shows which targets the running system actually reached, which is the fastest way to see that a host stopped short of `multi-user.target` after a failed unit; the third lists what has been enabled, i.e. what has a `.wants/` symlink pointing at it somewhere. ## Why interviewers ask it It is a cheap check that you understand systemd is graph-driven rather than script-driven. A candidate who says "you edit inittab" or "you set the runlevel in a config file" has not operated a modern Linux host; one who says "default.target is a symlink, and everything hangs off it" has.

  • What is the difference between systemctl isolate multi-user.target and systemctl set-default multi-user.target?
    `isolate` acts on the running system: it starts the named target and stops every unit not required by it, taking effect immediately and lasting only until reboot. `set-default` writes the `default.target` symlink and changes nothing right now — it decides what the *next* boot activates. Recovering a host usually wants `isolate`; fixing a misconfigured server image wants `set-default`.
  • How would you find out why a particular service came up at boot when nothing in default.target names it?
    Look at the reverse dependency: `systemctl list-dependencies --reverse <unit>` walks upward to whatever pulled it in. The usual answer is a `.wants/` symlink created by `systemctl enable` from the unit's own `[Install]` section, which you can see with `systemctl cat <unit>` and confirm with `systemctl is-enabled <unit>`.

saying these in an interview costs you the question

  • Says the boot target is set in a config file rather than a symlink
  • Confuses systemctl isolate with systemctl set-default
  • Thinks set-default takes effect immediately on the running system
  • Believes each service has its own boot-time entry rather than being pulled in
  • Claims a runlevel number is stored somewhere on disk

context