#### # # #### ##### ###### # # ##### #### # # #### # # ####
# # # # # # ## ## # # # # # # # # # #
#### # #### # ##### # ## # # # #### # # # #### ####
# # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # #
#### # #### # ###### # # ##### #### #### #### # # ####
reasons systemd is hostile to simplicity, choice, debuggability, and the unix tradition.
systemd started as a replacement for sysvinit and quickly absorbed logging, device management, network configuration, time synchronization, login handling, dns resolution, container management, and more. the result is a single massive project that touches nearly every part of userspace. an init system should start processes and stay out of the way. systemd turned itself into the operating system.
the classic design rule was "do one thing and do it well." systemd does dozens of things and does several of them poorly. each new component increases the surface area, the attack surface, and the number of ways the whole machine can fail. when everything is tightly coupled, a bug in the journal or in udev can take down the boot process. modular tools can be replaced or ignored. a monolith cannot.
journald stores logs in a binary format. plain text files that can be read with cat, grep, tail, and less are treated as second-class. binary logs require special tools, make remote collection more complicated, and turn simple debugging into an exercise in journalctl flags. when the journal itself is corrupted or the system is partially broken, the logs become harder to recover. text files fail more gracefully.
every release seems to absorb another traditional daemon. networkd, resolved, timesyncd, homed, and the rest expand the project's reach. the official justification is always "integration" or "consistency." the practical effect is that distributions that ship systemd slowly lose the ability to swap individual components. once the dependencies are baked in, "optional" becomes theoretical.
many packages and desktop environments now assume systemd is present. dbus activation, cgroup management, and various unit files create soft lock-in. switching to another init requires fighting the packaging system and often rebuilding or patching software. the more software is written against systemd apis, the harder it becomes to leave. this is the opposite of the loose coupling that made unix systems durable.
unit files, drop-ins, generators, targets, slices, scopes, and a large configuration surface make simple tasks verbose and error-prone. the documentation is long because the system is large. newcomers are told to learn an entire parallel vocabulary instead of editing a few scripts. complexity is sold as power. in practice it is a tax paid every time something goes wrong at boot.
when a service fails to start, the path to understanding often involves journalctl, systemctl status, systemctl cat, and various show commands. the old model of readable init scripts and clear process trees has been replaced by a state machine whose internal decisions are not always obvious. failures that used to be visible in a few lines of shell now require specialized knowledge of systemd internals.
systemd makes heavy use of cgroups and treats them as a central mechanism for resource control and process tracking. while cgroups are useful, making them mandatory infrastructure increases the minimum complexity of the system. other init systems can use cgroups when needed without requiring every service to be managed through the same hierarchy.
systemd is tightly bound to linux kernel features. it is not intended to run on other unix systems and makes little effort to remain portable. this is a deliberate choice, but it means the largest free init system is also the one least useful outside the linux monoculture. portable tools survive platform changes. platform-specific megaprojects do not.
services, sockets, mounts, timers, paths, and devices are all forced into the same abstraction. the uniformity looks elegant on paper. in practice it means that simple cron jobs become timer units, simple mount points become mount units, and operators must learn systemd's model even for tasks that never needed it. not every problem benefits from being expressed as a unit file.
a large codebase written in c with a wide attack surface is hard to secure. systemd has had its share of vulnerabilities. the project also pushes features such as dynamic users, private tmp, and various sandboxing options. some of these are useful. others add complexity that itself becomes a source of misconfiguration. security is improved more by reducing the amount of privileged code than by adding more configuration knobs.
features useful for a graphical workstation (session management, seat handling, user units) are carried into server environments where they add little value and extra moving parts. the same binary is expected to serve both roles. the result is that minimal server installs still pull in machinery designed for laptops and desktops.
once a distribution commits to systemd, reversing the decision becomes extremely expensive. packages start depending on libsystemd, on specific unit behaviors, and on journald. alternative inits are relegated to niche ports or abandoned. the cost of switching rises every year. this is how soft monopolies form in free software.
proponents argue that tight integration produces a better user experience. the counter-argument is that integration without clear boundaries produces systems that are difficult to understand, difficult to repair, and difficult to replace piece by piece. unix succeeded in part because components could be swapped. systemd optimizes for a single coherent stack at the expense of that flexibility.
the manual pages and the design documents are extensive because they have to be. learning enough to administer a systemd system confidently takes far longer than learning a traditional init. the knowledge is also less transferable. experience with one set of shell scripts translates more easily across systems than experience with one particular unit dialect.
parallel startup, socket activation, and generator scripts make the boot process faster on paper and more opaque in practice. when something fails early, the failure mode is often a long wait followed by a rescue shell or a cryptic journal entry. linear, predictable scripts are slower but easier to reason about when the machine will not come up.
systemd did solve real problems with sysvinit: lack of dependency handling, poor parallelization, and awkward service supervision. those problems could have been fixed with smaller, more focused tools. instead the solution was a single project that kept growing. the existence of a real problem does not justify an unbounded solution.
the project is tightly controlled. technical disagreements frequently become personal. critics are often dismissed as anti-progress or as people who simply do not understand modern systems. the result is a culture that produces a lot of code and relatively little willingness to question the overall direction. large projects need internal resistance to scope creep. systemd has shown limited capacity for that resistance.
when the init system handles restart policies, resource limits, dependency ordering, and logging, application developers are encouraged to treat the service manager as a black box. the old discipline of writing programs that behave well under simple supervision is weakened. the system becomes smarter so that individual components can become dumber. that tradeoff is not free.
you do not have to accept systemd as the only modern option.
(c) 2026 vextoly