Skip to content

Glossary

launchd

launchd is PID 1 on macOS: the init system and service manager. LaunchDaemons vs LaunchAgents, plist locations, launchctl basics and on-demand launching.

launchd is the very first userspace process started by the kernel — PID 1. It is simultaneously:

  • The init system (the thing the kernel execs after boot).
  • The service manager (the thing that loads daemons, agents, and XPC services).
  • The socket and event activator (it can hold a listening socket or Mach port and start a daemon on first use).

What is launchd on macOS?

On Linux you would reach for systemd, init, or cron; on macOS all of those jobs belong to launchd. Once the kernel finishes booting, load_init_program() execs /sbin/launchd as process 1. Every other userland process on the system — WindowServer, loginwindow, your shell, the apps you open — is started by launchd or by something launchd started. If launchd dies, the kernel panics.

apple-oss-distributions/xnubsd/kern/kern_exec.cload_init_program() — where the kernel execs /sbin/launchd as PID 1.View on GitHub(line —)

Each unit of work launchd manages is a job, described by a property list (launchd.plist) with a unique Label, the program to run (Program / ProgramArguments), and the conditions under which to run it.

LaunchDaemons vs LaunchAgents

The same plist format is used for two kinds of jobs, and the directory a plist lives in decides which one it is:

LocationKindRuns as / when
/System/Library/LaunchDaemons/Apple daemonsSystem-wide, usually root, from boot (read-only on the sealed system volume)
/Library/LaunchDaemons/Third-party daemonsSystem-wide, root or the UserName in the plist, from boot, no GUI access
/System/Library/LaunchAgents/Apple agentsPer user, inside each logged-in user's session
/Library/LaunchAgents/Third-party agentsPer user, for every user who logs in
~/Library/LaunchAgents/Per-user agentsOnly for that user, when they log in

Daemons are background services with no user context — they start before anyone logs in and can't draw UI. Agents run on behalf of a logged-in user in that user's GUI session, so they can talk to the window server, the pasteboard and the user's keychain.

Apps shipped since macOS 13 usually register their helpers through SMAppService instead of dropping plists into these folders; either way they appear under System Settings → General → Login Items.

On-demand launching

launchd's defining feature is that jobs don't need to run until something needs them. Instead of starting every service at boot, launchd holds the resource and starts the job lazily:

  • MachServices — launchd registers the service name in the bootstrap namespace and holds the receive right. The first Mach message (or XPC connection) to that name starts the daemon, which then checks the port in.
  • Sockets — launchd listens on a socket and hands it to the job on the first connection (inetd-style activation).
  • StartInterval / StartCalendarInterval — periodic runs, the macOS replacement for cron.
  • WatchPaths / QueueDirectories — run when a file or directory changes.
  • RunAtLoad / KeepAlive — start immediately, and optionally restart if the job exits.

Because clients hold names rather than PIDs, an idle daemon can exit and be relaunched transparently on the next request. launchd also assigns each job its jetsam priority band, which tells the kernel what to kill first under memory pressure.

launchctl basics

launchctl is the command-line interface to launchd. Modern macOS addresses jobs by domain — system for daemons, gui/<uid> for a logged-in user's agents:

# Load / unload a job (replaces the legacy `load` / `unload`)
sudo launchctl bootstrap system /Library/LaunchDaemons/com.example.helper.plist
launchctl bootout gui/$(id -u)/com.example.agent

# Inspect
launchctl list                                  # jobs in your domain, with PID and last exit status
launchctl print system/com.apple.mDNSResponder  # full state of one job

# Control
sudo launchctl kickstart -k system/com.example.helper   # (re)start now
sudo launchctl disable system/com.example.helper        # persistently disable

Validate a plist before loading it with plutil -lint file.plist.

Apple open-sourced the original launchd at apple-oss-distributions/launchd, though the project hasn't been updated there in some time — modern macOS uses an internal evolution (now tightly coupled with libxpc). The open repo is still useful for understanding the design. For where launchd sits in the boot sequence, see How macOS boots.

See also: jetsam, XPC, Mach message.