Systemd Target Units: Managing System States Gracefully

In the world of systemd, target units play a critical role in orchestrating the state of a Linux system. While services do the actual work, targets define the bigger picture: when and in what context those services should run. Think of them as milestones or checkpoints in the boot process — or custom-defined states that bundle related units together.

In this article, we’ll demystify systemd targets, explore their role, explain how to create custom targets, and show real-world examples where custom targets provide meaningful improvements in system management.


What is a Target Unit?

A target unit is a systemd unit of type .target. Its main purpose is to group and synchronize other units. Targets don’t do anything directly — they’re placeholders for sets of units (services, sockets, devices, etc.) that should start or stop together.

They are also used to express a system’s state. For example:

  • basic.target: Minimal system initialization
  • multi-user.target: Text-based system fully operational
  • graphical.target: GUI session ready
  • rescue.target: Emergency shell with minimal services

Anatomy of a Target Unit

A typical target unit file is quite simple:

[Unit]
Description=My Custom Target
Requires=my-custom-service.service
After=network.target

[Install]
WantedBy=multi-user.target

Where:

  • Requires=: Units that must be activated when this target is activated
  • After=: Defines the order — ensures this target starts after the listed unit
  • WantedBy=: Allows the target to be enabled via systemctl enable

Targets vs Runlevels

If you’re coming from the SysVinit world, some targets replace* the old runlevel system:

Runlevelsystemd Equivalent
0poweroff.target
1rescue.target
3multi-user.target
5graphical.target
6reboot.target

* Not every systemd target unit can be used like a runlevel — only those with the AllowIsolate option set to yes.

You can change the default target (equivalent to default runlevel) like so:

sudo systemctl set-default multi-user.target

Common Built-in Targets

default.target

The default system state — typically graphical.target or multi-user.target.

network.target

Used to order units that require basic network availability. Not guaranteed to mean full connectivity.

network-online.target

Stronger than network.target — it ensures full network connectivity (used in server services).

multi-user.target

System is up and running in a non-graphical, multi-user mode.

graphical.target

All of multi-user.target plus graphical environment (X, Wayland, etc.).

rescue.target and emergency.target

Used for recovery and troubleshooting. Minimal services and user intervention possible.


Creating a Custom Target

Let’s say you want to boot your system into a special “Maintenance Mode” that only starts SSH and a monitoring agent.

Step 1: Define the Target

sudo nano /etc/systemd/system/maintenance.target
[Unit]
Description=Maintenance Mode
Requires=ssh.service monitoring-agent.service
After=network.target

[Install]
WantedBy=multi-user.target

Step 2: Enable and Use It

sudo systemctl daemon-reexec
sudo systemctl enable maintenance.target
sudo systemctl isolate maintenance.target

This tells systemd to stop all other units not required by maintenance.target and switch the system state accordingly.


Some Real-World Use Cases

Case 1: Safe Maintenance Boot

Create a custom target that disables user apps but enables SSH and logging. Perfect for system maintenance or updates.

Case 2: Boot Mode for Backup

Have a system boot into a backup target where only the backup agent and a safe read-only environment are available.

Case 3: Fast Boot for Headless Devices

Create a stripped-down target for embedded or IoT systems — load only essential networking, logging, and app services.

Case 4: Developer Mode

Define a target that launches dev tools, test databases, and editors, isolated from production services.


Inspecting Targets

List all loaded targets:

systemctl list-units --type=target

Show dependencies:

systemctl list-dependencies graphical.target

Show the current active target:

systemctl get-default

Switch to a new target:

sudo systemctl isolate rescue.target

Pro Tips

  • Always include After= and Requires= or Wants= to manage timing and dependencies.
  • Use PartOf= if you want a service to be stopped when a target is stopped.
  • Use isolate with caution — it stops everything not part of the new target.
  • Don’t forget WantedBy= in [Install] to allow enabling the target.

Final Thoughts

Targets in systemd aren’t just a modern replacement for runlevels — they’re a powerful way to group, order, and manage system states. Whether you’re trying to define a minimal environment, a special-purpose boot mode, or a group of logically related services, targets give you a clean, modular way to do it.

The more you embrace targets, the more maintainable and understandable your system configuration becomes. Create them with intent, document them clearly, and enjoy a more elegant Linux experience.

** Official documentation for systemd target units can be found here

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top