SysVinit, short for System V init, is the traditional init system of Unix-like operating systems, in which the first user-space process reads /etc/inittab and starts or stops services by running shell scripts grouped into runlevels. In Linux system initialization, it was the standard way to bring a machine from kernel startup to a usable state for roughly two decades.
Most major distributions replaced SysVinit with systemd in the mid-2010s, but SysVinit remains relevant: Devuan and some embedded and minimal systems still use it, many legacy services ship init scripts in its format, and systemd keeps compatibility layers that read those scripts.
How SysVinit boots a system
After the boot loader, such as GRUB, loads the kernel and the initramfs, the kernel starts /sbin/init as process ID 1. SysVinit’s init then reads `/etc/inittab`, which defines the default runlevel, the system initialization script and the processes to keep running, such as login prompts on virtual consoles.
Init first runs a system initialization script that mounts file systems, checks disks and sets the hostname. It then enters the default runlevel by calling the `rc` script, which executes the scripts linked in that runlevel’s directory one after another in a fixed order. This sequential model is simple and predictable, but it makes boot time the sum of all script durations.
| Stage | Component | What happens |
|---|---|---|
| Process 1 starts | /sbin/init | Kernel hands control to init |
| Configuration read | /etc/inittab | Default runlevel and respawn entries are loaded |
| System initialization | Distribution sysinit script | File systems mounted, hostname and clock set |
| Runlevel entry | rc with the runlevel number | Kill scripts then start scripts run in order |
| Login services | getty entries in inittab | Consoles offer login prompts, respawned on exit |
Runlevels and init scripts
A runlevel is a numbered system state that determines which services run. Each runlevel has a directory such as /etc/rc3.d containing symbolic links to scripts in /etc/init.d. Links starting with S are started and links starting with K are killed, and a two-digit number after the letter sets the order, so S20network runs before S80apache.
| Runlevel | Usual meaning | Notes |
|---|---|---|
| 0 | Halt | System shuts down |
| 1 or S | Single-user mode | Maintenance with minimal services |
| 2 | Multi-user | On Debian, the full default level |
| 3 | Multi-user with networking, text mode | Typical server default on Red Hat systems |
| 4 | Unused or locally defined | Available for custom configurations |
| 5 | Multi-user with graphical login | Desktop default on many distributions |
| 6 | Reboot | System restarts |
Each init script accepts standard arguments such as start, stop, restart and status. Administrators use tools such as service, chkconfig on Red Hat systems or update-rc.d on Debian systems to run scripts and manage links, and telinit or init followed by a number to switch runlevels at runtime.
SysVinit compared with modern init systems
The main criticisms of SysVinit concern serial startup, the lack of service supervision and the reliance on hand-written scripts. Its successors address these in different ways.
| Init system | Service definition | Startup model | Supervision |
|---|---|---|---|
| SysVinit | Shell scripts in /etc/init.d | Sequential by link order | Only for inittab respawn entries |
| systemd | Declarative unit files | Parallel, dependency-based, socket activation | Built in, with cgroups tracking |
| OpenRC | Shell-based scripts with dependency headers | Dependency-based, optional parallelism | Optional supervisor |
| Upstart | Event-based job files | Event-driven | Built in, now discontinued |
With SysVinit, a crashed daemon stays down unless an external tool restarts it, and service state is inferred from PID files that can become stale. Systemd tracks every process of a service in a control group and replaces runlevels with systemd targets, mapping runlevel 3 to multi-user.target and runlevel 5 to graphical.target.
Working with SysVinit scripts today
On systemd distributions, scripts in /etc/init.d are still honored through the systemd-sysv-generator, which creates wrapper units at boot. Dependency information comes from LSB header comments such as Required-Start and Default-Start at the top of each script.
| Task | SysVinit | systemd |
|---|---|---|
| Start a service | service nginx start | systemctl start nginx |
| Enable at boot on Red Hat systems | chkconfig nginx on | systemctl enable nginx |
| Enable at boot on Debian systems | update-rc.d nginx defaults | systemctl enable nginx |
| Change system state | telinit 3 | systemctl isolate multi-user.target |
| Check the current state | runlevel | systemctl get-default |
When migrating a legacy service, the recommended practice is to write a native unit file rather than rely on the generator, because a native unit gains supervision, resource limits and reliable logging through journalctl.
Strengths, limitations and pitfalls
SysVinit’s main strength is transparency: every step is a readable shell script, and debugging means reading code and adding echo statements. It has few dependencies, which suits small embedded systems.
- Slow boot: scripts run one at a time, and a script waiting on a network timeout delays everything after it.
- Stale PID files make
statusreport a service as running when it has crashed, or block restarts. - Fragile ordering: two-digit sequence numbers do not express real dependencies and break when packages choose conflicting values.
- Inconsistent scripts: each package author implements start and stop logic differently, so behavior varies.
- Environment differences: scripts run with a minimal environment, so commands that work interactively can fail at boot.
In simple terms
When a computer starts, something has to switch on all the background programs it needs. SysVinit is an older, very simple way to do that.
It works like a checklist read from top to bottom. Each line starts one program, and the next line waits until the previous one is done. This makes it easy to understand. It is also slower than newer systems, which can start many programs at once and restart them if they crash.
A practical example
A manufacturing company operates an older Linux-based machine controller that still uses SysVinit. A vendor supplied a monitoring daemon with an init script installed as S99monitor in runlevel 3, the default runlevel defined in /etc/inittab.
After a power cut, the daemon fails to start because its script runs before a network share is mounted by a later-added S99mountshare link, and both share the same sequence number. The engineer renames the mount link to S50 so it runs earlier and adds a respawn entry in inittab for the critical process, giving it basic automatic restarts. The next outage test shows a clean boot in the correct order, and the team documents the change while planning a migration to a newer platform with native service supervision.