Skip to content

Coming from systemd, OpenRC or runit

If you already run services on another init or service manager, the day-to-day gestures transpose almost one for one. This page maps the commands and concepts you know to their 66 equivalents. The model underneath differs more than the spelling does — trees are managed objects, service definitions are compiled before anything starts, and a reaction lives in the service it affects — and where 66 stands among init systems covers that side.

For migrating between 66 versions, see upgrade and the Rosetta stone instead.

Commands

You want to… systemd OpenRC runit 66
Start now systemctl start foo rc-service foo start sv up foo 66 start foo
Stop now systemctl stop foo rc-service foo stop sv down foo 66 stop foo
Enable at boot systemctl enable foo rc-update add foo ln -s … 66 enable foo
Disable at boot systemctl disable foo rc-update del foo rm … 66 disable foo
Enable and start systemctl enable --now foo 66 enable --start foo
Restart systemctl restart foo rc-service foo restart sv restart foo 66 restart foo
Reload (SIGHUP) systemctl reload foo rc-service foo reload sv reload foo 66 reload foo
Status & recent log systemctl status foo rc-service foo status sv status foo 66 status foo
Read the log journalctl -u foo log file log file 66 log foo
Follow the log journalctl -fu foo tail -f tail -f 66 log --follow foo
Apply an edited unit systemctl daemon-reload 66 reconfigure foo

Concepts

Concept systemd OpenRC runit 66
Service definition foo.service unit /etc/init.d/foo script /etc/sv/foo/run foo frontend file (INI)
Long-running daemon Type=simple/notify supervisor/script the norm Type = classic
Run-once task Type=oneshot script, no daemon Type = oneshot
Readiness notification Type=notify ./check Notify = <fd>
Group / target .target runlevel runsvdir dir tree
Drop privileges User= chpst -u RunAs = user
Resource limits Limit*= rc_ulimit softlimit [Execute] Limit* keys
Environment Environment= / EnvironmentFile= conf.d ./env [Environment] section
Session variables handed to every service manager-level environment command 66 env
React to a file change / a schedule / another service separate trigger unit [Event] section, in the reacting service itself

66-only commands

These have no direct counterpart elsewhere — they fall out of 66's parse-then-supervise model and its tree/snapshot features. Coming from another init, these are the genuinely new tools in your hand:

Command What it does Closest elsewhere
66 parse Compile a frontend file into 66's internal form, without starting anything — (units/scripts are read directly)
66 free Stop a service and drop it from the live scandir (unsupervise), keeping it parsed and enabled — (stopping never unsupervises)
66 remove Erase everything 66 generated for the service (parsed form + state); your frontend file is kept manual rm of the unit + systemctl daemon-reload
66 reconfigure Stop, unsupervise, re-parse and restart in one step, to apply an edited frontend partial: systemctl daemon-reload then restart
66 scandir Create / start / stop your own supervision tree (66-scandir) partial: systemd does run a per-user manager, but the system instance spawns and controls it; here the tree is yours to create, start and stop
66 tree Create and manage named groups of services as first-class objects, with their own dependencies systemd .target (static config, not a managed object)
66 snapshot Capture, restore or transfer the whole 66 ecosystem (e.g. to clone it onto another machine)
66 resolve Print the complete service as the system resolved it — every field, the generated run/finish scripts, the resolved on-disk and live paths OpenRC/runit: none; systemd systemctl show is nearest but reports runtime properties, not the compiled definition
66 state Dump a service's runtime state flags (parsed, supervised, up…), for debugging
66 configure Edit a service's versioned environment configuration partial: drop-ins / EnvironmentFile (not versioned)

Built for scripting. 66 resolve is the authoritative view of a service — exactly what 66 itself acts on — and, like every 66 command, it is made to be parsed by scripts. Field selectors give you raw, label-free values: 66 resolve -n -f run foo prints just the generated run script, 66 status -n -f pid,status foo prints exactly those two columns. (-f picks fields, -n drops the labels.) OpenRC and runit offer no structured service introspection at all; systemd's systemctl show is the closest, but it exposes the manager's runtime properties rather than the service's full compiled form the way resolve does.

A few differences worth knowing

Daemons must run in the foreground. Like any process supervisor, 66 supervises the process it launches. The first choice is always to pass the "don't fork" flag (--foreground, -d, --nofork…). See troubleshooting.

When a daemon offers no such flag — the systemd Type=forking case — the 66-ns tool (from the 66-tools package) supervises it anyway by giving it a private PID namespace, inside which 66-ns becomes a transparent pid-1 proxy that follows the daemon across its forks. Wrap the command in [Start]:

[Start]
Execute = ( 66-ns -o unshare=pid dhcpcd )

See the 66-ns documentation for the details, including the optional --pidfile for daemons that keep a sibling process alive.

Ordering and requirement are one relation, in two directions. systemd splits ordering (After=) from requirement (Requires=). 66 folds both into a single relation: a dependency is started first and is required. You can state it from either end — Depends = ( db ) ("I need db") or, from the other side, RequiredBy = ( webapp ) ("webapp needs me"), the reverse link that lets a service attach itself to others without editing their files (systemd's RequiredBy=/WantedBy=). You declare only direct links; 66 resolves the whole chain in both directions. See dependencies and ordering.

A session can hand variables to services after the fact. A scandir starts long before a session exists, so its environment is frozen without DISPLAY, WAYLAND_DISPLAY or XAUTHORITY. 66 env is the way in: 66 env import DISPLAY XAUTHORITY copies the variables from the caller's environment, 66 env set KEY=value publishes an explicit value, 66 env unset withdraws one, 66 env list shows what is published. Every service of that scandir picks it up at its next start, without declaring anything in its frontend, and the published value is merged last — it wins over the frontend, the service configuration and the ImportFile files.

Where 66 goes further: publishing or withdrawing a variable also raises an event (env.DISPLAY, unenv.DISPLAY), so a service can be started by the arrival of the value it needs and stopped by its disappearance, rather than being restarted by hand afterwards. See the event system. Nothing published survives the scandir; there is no persistent manager environment to clean up.

Reacting to an event is declared in the service that reacts, not next to it. "Restart foo when this file changes" is usually expressed with a second file that names foo as the thing to activate, so the rule lives outside foo and foo never mentions it. 66 reverses the direction: foo carries an [Event] section saying what happens to itself, and a reaction has no target key at all — 66-eventd can only run the verb on the service that declared it.

The practical difference shows up when you maintain a system rather than write one. Everything that can restart foo at 3 a.m. is written in foo's own frontend, so you read one file instead of searching the whole service tree. And subscribing a service to an existing event changes exactly one file — its own — never a file belonging to a service you do not own. The only key that reaches outward, Emit, raises a name, never a command: whoever cares subscribes on their side. See the event system.

Applying config changes is per-service, not global. systemctl daemon-reload re-reads every unit file for the whole manager at once — a global operation that, on its own, restarts nothing. 66 reconfigure foo is the opposite: it targets one service (and its dependency chain), re-parsing its frontend and bringing it back up. There is no "reload everything" switch in 66 — you apply changes service by service, or a whole tree at a time. So the daemon-reloadreconfigure row above is a rough mapping, not an exact equivalence.

A unit, translated

A typical systemd unit:

[Unit]
Description=My daemon
After=network.target
Requires=network.target

[Service]
Type=simple
ExecStart=/usr/bin/mydaemon --foreground
User=myuser

[Install]
WantedBy=multi-user.target

becomes, as a 66 frontend file named mydaemon:

[Main]
Type = classic
Description = "My daemon"
Depends = ( network )

[Start]
RunAs = myuser
Execute = ( /usr/bin/mydaemon --foreground )

and you place it in /etc/66/service, then 66 enable --start mydaemon. The WantedBy target maps to enabling it (optionally into a named tree).

Where to go next