GICT knowledge base
Understanding Runlevels and Systemd Boot Targets in Linux
Published
If you spend enough time working with Linux, you’ll notice something interesting: no matter which flavor you use, the boot process is both familiar and full of surprises. Sometimes your system boots straight to a text login, other times you’re welcomed by a graphical desktop. When things go wrong, maybe you end up in “single-user mode” or “rescue mode.” If you’ve ever wondered how Linux decides what to start at boot or how to control what comes up, and in what order you’re in the right place.
The answer lies in two key concepts: runlevels (from the old SysVinit days) and systemd boot targets (the modern approach). Understanding these is essential for any Linux admin, developer, or power user. Not only does it help you troubleshoot boot issues, but it also lets you fine-tune your environment for servers, desktops, or anything in between.
In this guide, we’ll take a deep dive into runlevels and systemd targets: what they are, how they evolved, and how you can use them to control your system’s behavior. We’ll look at practical commands, real-world scenarios, and some lessons learned from years of managing Linux systems. Whether you’re a beginner or just need a refresher, you’ll walk away with both the “how” and the “why” of this foundational Linux topic.
The History: Where Runlevels Come From
Let’s start with a bit of history because understanding where runlevels came from makes it much easier to appreciate systemd targets.
The SysVinit Legacy
In the early days of Linux, most distributions used a system called SysVinit to manage the boot process and services. When your computer powered on, SysVinit started the kernel, which then ran a special process called init (with process ID 1). The job of init was to launch all the background services (daemons), mount filesystems, and eventually bring the system to a usable state.
To organize all these tasks, SysVinit used runlevels each one representing a different state of the system. Think of runlevels as “modes” your system could be in, each with its own set of running services.
Here’s a classic mapping of runlevels:
| Runlevel | Name | Typical Purpose |
|---|---|---|
| 0 | Halt | Shutdown |
| 1 | Single-user | Maintenance (root only, minimal services) |
| 2 | Multi-user | Multi-user, no network (Debian/Ubuntu) |
| 3 | Multi-user | Multi-user, network (no GUI) |
| 4 | Undefined | User definable (rarely used) |
| 5 | Graphical | Multi-user, network, GUI (X11) |
| 6 | Reboot | Reboot |
How Did It Work?
On boot, SysVinit read /etc/inittab to determine the default runlevel. Then it started or stopped services based on scripts in /etc/rcN.d/ (where N was the runlevel number). For example:
- Runlevel 3: Start network, SSH, and all multi-user services, but not a graphical desktop.
- Runlevel 5: Start everything in runlevel 3, plus the graphical login manager.
You could change runlevels on the fly (e.g., init 3 or telinit 1) handy for troubleshooting.
Why Did We Move On? The Limits of Runlevels
SysVinit and runlevels worked, but they weren’t perfect:
- Rigid Structure: Only seven runlevels, and only one could be active at a time.
- No Parallelization: Services started one after another, making boot slow.
- Poor Dependency Management: Couldn’t easily express “only start X after Y and Z.”
- Limited Flexibility: Custom runlevels were rare and awkward.
- No Standardization: Different distros used runlevels differently (e.g., Debian’s runlevel 2 was multi-user with networking, while on Red Hat, it was single-user).
As Linux systems became more complex and faster boot times became important (especially for desktops and servers), something better was needed.
Enter systemd: The Modern Way
Systemd is now the default init system for nearly all major Linux distributions: Fedora, Ubuntu, Debian, CentOS, openSUSE, Arch, and more. It’s a controversial topic among old-school admins, but there’s no denying it’s here to stay.
What Is systemd?
At its core, systemd is a suite of tools that manages the whole boot process, services (called “units”), logging, device handling, and more. It starts the system, brings up services in parallel (for speed), and can manage dependencies and state better than SysVinit ever could.
Boot Targets: The New “Runlevels”
Instead of runlevels, systemd uses targets. Targets are unit files that group services and dependencies together so they’re like runlevels, but much more flexible.
Some common targets:
| Target Name | Purpose | (Roughly) Equivalent Runlevel |
|---|---|---|
| rescue.target | Single-user mode for maintenance | Runlevel 1 |
| multi-user.target | Multi-user, network, text login | Runlevel 3 |
| graphical.target | Multi-user, with graphical desktop (GUI) | Runlevel 5 |
| reboot.target | Reboot the system | Runlevel 6 |
| poweroff.target | Shut down the system | Runlevel 0 |
| emergency.target | Minimal rescue shell (even less than rescue) | N/A |
But here’s the key: you can define your own targets, add dependencies, and have multiple targets “active” at once.
The Anatomy of a systemd Boot
Let’s walk through what actually happens when you boot a modern Linux system with systemd:
- Firmware (BIOS/UEFI) Loads the Kernel: The bootloader hands control to the Linux kernel.
- Kernel Starts systemd: The kernel launches process 1, which is now /sbin/init (a symlink to systemd).
- systemd Reads Default Target: The default target is usually graphical.target or multi-user.target, as specified in /etc/systemd/system/default.target.
- systemd Resolves Dependencies: systemd figures out which services, mounts, and other units are needed for this target.
- Parallel Startup: systemd starts all units as fast as possible but respects dependencies.
- Login Prompt or Desktop: When the target is reached, you get your login prompt (text or graphical).
Mapping Runlevels to systemd Targets
Most systemd-based distros still support the old runlevel commands for compatibility. Here’s how the mapping works:
| Runlevel | SysV Meanings | systemd Target |
|---|---|---|
| 0 | Halt | poweroff.target |
| 1 | Single-user | rescue.target |
| 2, 3, 4 | Multi-user | multi-user.target |
| 5 | Graphical | graphical.target |
| 6 | Reboot | reboot.target |
For example, if you run init 3 or telinit 3 on a modern system, systemd interprets that as multi-user.target.
How to Check and Change Boot Targets
1. View the Current Target
systemctl get-default
This tells you what target your system boots into by default (e.g., graphical.target or multi-user.target).
2. List All Targets
systemctl list-units --type=target
This shows all targets currently active.
3. Change the Default Boot Target
To set your system to boot to a text login (no GUI):
sudo systemctl set-default multi-user.target
To switch back to graphical boot:
sudo systemctl set-default graphical.target
4. Switch Targets on the Fly
If you’re at a text login and want to start the GUI:
sudo systemctl isolate graphical.target
If you want to go back to text mode:
sudo systemctl isolate multi-user.target
The isolate command transitions the system to the specified target, stopping services not needed for the new target and starting any additional ones.
Practical Scenarios & Use Cases
Scenario 1: Troubleshooting a Broken Desktop
Suppose you update your system and suddenly the graphical desktop won’t start. Maybe it crashes or you get a black screen. To troubleshoot:
- Boot the system.
- At the GRUB menu, edit the boot parameters and add
systemd.unit=multi-user.targetto boot into text mode. - Log in at the console and check logs, drivers, or try reinstalling GUI components.
- Once fixed, return to
graphical.target.
Scenario 2: Running a Headless Server
For servers, you almost never need a graphical desktop. Set the default target to save resources:
sudo systemctl set-default multi-user.target
Your server will boot to a fast, text-only login.
Scenario 3: Single-User or Rescue Mode
If your system can’t mount a disk or you break /etc/fstab, boot into rescue mode:
- At the GRUB menu, press e to edit the boot line.
- Add
systemd.unit=rescue.targetorsystemd.unit=emergency.target. - The system boots into a root shell with minimal services.
How Targets Work Behind the Scenes
A target is just a special kind of systemd unit file (a .target file) that groups other units together. You’ll find these in /usr/lib/systemd/system/ or /etc/systemd/system/.
For example, multi-user.target might “require” networking, SSH, and cron, but not the graphical display manager. graphical.target “requires” everything in multi-user.target, plus your X11 display manager.
You can see what services are part of a target:
systemctl list-dependencies multi-user.target
systemctl list-dependencies graphical.target
want to see what runs at boot? Try:
systemctl list-dependencies default.target
Customizing and Creating Your Own Targets
One of systemd’s strengths is that you can create your own targets perfect for custom server roles or special maintenance modes.
Suppose you want a special “maintenance” target that boots into text mode, but only starts a few key services. You could:
- Copy multi-user.target to a new name in /etc/systemd/system/maintenance.target.
- Edit the .target file to “require” only the services you want.
- Set it as your default with
systemctl set-default maintenance.target.
Most users won’t need custom targets, but it’s a power tool for complex setups.
Advanced: systemd Rescue and Emergency Modes
- rescue.target: Like “single-user mode” in SysVinit. Root shell, minimal services.
- emergency.target: Even more minimal. Just a root shell, no filesystems mounted except /. Use if you’ve really broken something crucial.
To boot into these, edit your boot line in GRUB (press e), and add:
systemd.unit=rescue.target
or
systemd.unit=emergency.target
These modes are essential for disaster recovery, editing broken configs, or fixing disk issues.
The Role of runlevels and Compatibility
You might still see the runlevel command it prints the previous and current runlevel, for compatibility. On systemd systems, it’s really just a wrapper that maps targets to runlevels.
Try:
runlevel
You’ll get something like N 5 (N means “none before,” 5 is the current runlevel, i.e., graphical.target).
You can still use telinit 3 or init 5 and systemd will translate it, but it’s better to use systemctl commands for clarity.
Real-World Lessons: Mistakes, Pitfalls, and Tips
- Don’t Set the Boot Target Lightly: Changing the default target affects every boot. If you switch to multi-user.target and then forget, you might be surprised next time your server boots without a GUI.
- Be Careful with isolate: systemctl isolate stops services not in the new target. If you have custom services or dependencies, test carefully.
- Document Custom Targets: If you create or change targets, document what you’re doing future you and your teammates will thank you.
- Use the Logs: If the system doesn’t reach the expected target, check the logs:
journalctl -bThis shows all messages from the current boot.
- Know How to Recover: If you break the boot process (e.g., by misconfiguring a target or a service), boot into rescue.target or from a live USB, fix the files, and reboot.
FAQ
Are runlevels still used?
Not really. They’re supported for compatibility, but systemd targets are far more flexible.
Can I have multiple targets active at once?
Yes. Unlike runlevels, systemd can have multiple targets “active,” as targets are just groupings of units.
What’s the difference between rescue and emergency target?
Rescue has basic services and a root shell; emergency is the most minimal mode possible.
How do I see which services a target will start?
Use systemctl list-dependencies <target>.
How do I permanently set my system to boot without a GUI?
sudo systemctl set-default multi-user.target
Wrapping Up: Why This Still Matters
Even though most of us don’t edit /etc/inittab anymore, the concepts behind runlevels and systemd targets are still central to how Linux boots and runs. Mastering these lets you:
- Troubleshoot faster when something goes wrong
- Optimize boot times and resource usage
- Build reliable, flexible servers and desktops
- Recover from system failures with confidence
Whether you’re a server admin, a desktop power user, or just someone who likes to know how things work under the hood, understanding Linux boot targets is time well spent.
Conclusion
Linux has come a long way from the days of rigid runlevels and slow, sequential boots. While systemd isn’t perfect (and yes, it has its critics), it gives administrators and users more control and flexibility than ever before. Learning to work with systemd’s targets not just fighting against them makes you a better troubleshooter, a more confident admin, and someone who’s prepared for whatever your next Linux adventure throws at you.
So, next time you see your system dropping into a text login, or you need to recover from a rough update, remember: it’s all about targets. And now, you know exactly what to do.
Related guides
How to Set Up zram on a Small VPS
Configure zram on Ubuntu with kernel and swap checks. Understand compressed memory limits, monitor real use and avoid unsafe swap-file changes.
LinuxHow to Find Services That Need a Restart After Updates with needrestart
Find services using outdated libraries with needrestart on Ubuntu. Read restart reports, review automatic restart policy and plan maintenance safely.
LinuxHow to Limit a Linux Service’s Memory with systemd
Limit a Linux service with systemd MemoryHigh, MemoryMax and swap controls. Check cgroup support, diagnose pressure and remove only your own policy.
LinuxHow to Protect SSH with CrowdSec on Ubuntu
Protect SSH with CrowdSec on Ubuntu. Connect log detection to firewall enforcement and test temporary blocking without losing administrator access.
