How to Use the launchctl Command in macOS Terminal to Manage LaunchDaemons and LaunchAgents

On macOS, background system daemons, user startup utilities, and scheduled maintenance tasks are not managed by Linux-style systemd or traditional cron daemons. The macOS service architecture is unified under launchd, Apple’s master init and process supervisor. The command-line utility launchctl interfaces with launchd, allowing system administrators, software developers, and MDM engineers to load, bootstrap, kickstart, and debug background background property lists (.plist files).

LaunchDaemons vs LaunchAgents: Understanding the Hierarchy

The launchd architecture divides services into two distinct scopes based on execution privileges and user login state:

Service Type Configuration Directory Execution Context Run Requirements
System LaunchDaemons /Library/LaunchDaemons/ Root (System-wide) Runs before user login; no GUI access.
Global LaunchAgents /Library/LaunchAgents/ Logged-in User Runs per-user upon GUI login; can display alerts.
User LaunchAgents ~/Library/LaunchAgents/ Specific User Account Personal automated user scripts and tools.

Modern launchctl Syntax: bootstrap and bootout

Older macOS guides frequently recommend legacy commands like launchctl load and launchctl unload. In modern macOS (macOS 11 Big Sur through macOS 15 Sequoia), Apple replaced these with domain-targeted subcommands:

# Determine current user domain target (GUI Domain)
echo "gui/$(id -u)"

# Determine system root domain target
echo "system"
Legacy Command Modern Replacement Functional Scope
launchctl load <file> launchctl bootstrap gui/<uid> <file> Registers and initializes a LaunchAgent plist.
launchctl unload <file> launchctl bootout gui/<uid> <file> Unregisters and terminates the active service.
launchctl start <label> launchctl kickstart -k <target>/<label> Kills running instance and triggers an immediate restart.

Creating a Custom Scheduled LaunchAgent Plist

To create a scheduled background task that executes an automated backup script every morning at 08:30 AM, create a property list file in ~/Library/LaunchAgents/com.user.backup.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.backup</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/zsh</string>
        <string>/Users/username/Scripts/backup.sh</string>
    </array>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>8</integer>
        <key>Minute</key>
        <integer>30</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/tmp/backup.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/backup_error.log</string>
</dict>
</plist>

Loading and Managing the Service with launchctl

Once the plist is written and saved, register it with the user’s GUI session:

# Register the LaunchAgent plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.backup.plist

# Verify that the service is registered in launchd
launchctl print gui/$(id -u)/com.user.backup

# Manually trigger immediate execution for testing
launchctl kickstart -k -p gui/$(id -u)/com.user.backup

The -p flag prints the process ID (PID) assigned to the running process, while -k terminates any existing instance to ensure a clean start.

Unloading and Removing Services

To disable the scheduled job and unregister it from launchd memory:

launchctl bootout gui/$(id -u)/com.user.backup

Mastering modern launchctl bootstrap mechanics provides macOS engineers with reliable process supervision, high-precision task automation, and enterprise-grade daemon management.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.