cheat sheet

softwareupdate

Deep-dive on softwareupdate(8), Apple's CLI for macOS system updates — listing pending updates, installing recommended-only or specific items, scheduling, ignoring updates, installing Rosetta and Command Line Tools, and pairing with mas and brew for full system update automation.

softwareupdate — macOS Updates From the Terminal

What it is

softwareupdate(8) is Apple's command-line interface to the macOS Software Update mechanism — the same engine that powers System Settings → General → Software Update. It lists pending updates, downloads them, installs them (with or without restart), schedules background checks, and can ignore specific updates so they stop pestering the GUI. It's part of base macOS at /usr/sbin/softwareupdate and runs as root for any install operation. Reach for it when you're patching a fleet via SSH, scripting a CI runner's pre-job update, automating Rosetta installation on a new Apple Silicon Mac, or just want to apply security updates without opening System Settings. The Apple-developer-tools subset (Command Line Tools, Xcode beta releases) is also installable here, although Xcode itself comes from the App Store via mas or the GUI. For App Store apps, pair softwareupdate with mas; for third-party CLI tools, pair with Homebrew.

[!WARN] MDM-managed fleets — the legacy update path is deprecated. As of macOS Tahoe 26, the classic MDM com.apple.SoftwareUpdate configuration-profile payload, the matching MDM commands (ScheduleOSUpdate, AvailableOSUpdates), and their related query keys are deprecated and Apple has stated they will be removed in the next major macOS release. New fleet deployments must move to Declarative Software Update Management (the softwareUpdate.settings and softwareUpdate.enforcement declarations). The softwareupdate(8) binary itself is unaffected and continues to work for interactive / local use — only the MDM scheduling channel is going away. Reference: Apple's What's new for enterprise in macOS Tahoe 26 (linked in Sources below).

Install

softwareupdate ships with every macOS install at /usr/sbin/softwareupdate. It cannot be installed, removed, or upgraded independently — it's part of the OS. Most operations require root, so use sudo.

bash
which softwareupdate
softwareupdate --help 2>&1 | head -20

Output:

text
/usr/sbin/softwareupdate
usage: softwareupdate <cmd> [<args> ...]

   -l | --list                       List all appropriate updates
   -d | --download                   Download Only
   -i | --install                    Install
        <label> ...                  specific updates
        -a | --all                   all appropriate updates
        -r | --recommended           only recommended updates
        -R | --restart               automatically restart (or shut down) if required
   --install-rosetta                 Install Rosetta 2
   --fetch-full-installer            Fetch full installer of macOS
   --list-full-installers            List the available full installers
   --ignore <label>...               Ignore specific updates
   --reset-ignored                   Clear the list of ignored updates
   --background                      Trigger a background scan and update operation
   --schedule                        Set automatic checking

Syntax

Three workflows cover 90% of usage: list pending (-l), install everything (-ia), or install a named subset (-i LABEL1 LABEL2). Add -R to restart automatically; add --agree-to-license for Rosetta and other EULA-bearing installs.

bash
sudo softwareupdate [--list | -l]                              # list pending
sudo softwareupdate --install --all [-R]                       # install everything
sudo softwareupdate --install --recommended [-R]               # only recommended
sudo softwareupdate --install LABEL [LABEL...]                 # install specific
sudo softwareupdate --install-rosetta --agree-to-license       # install Rosetta 2
sudo softwareupdate --ignore LABEL                             # ignore an update
softwareupdate --list-full-installers                          # list installable macOS versions
sudo softwareupdate --fetch-full-installer --full-installer-version 15.4

Output: (none — exits 0 on success)

Essential options

OptionMeaning
-l, --listList available updates (no install)
-d, --downloadDownload only — don't install
-i, --installInstall (requires sudo)
-a, --allApply to all pending updates
-r, --recommendedLimit to "recommended" updates (excludes betas, optional installs)
-R, --restartRestart or shut down automatically when an update demands it
--no-scanUse the cached update catalog (skip a fresh check)
--ignore LABELAdd LABEL to the ignored list
--reset-ignoredClear the ignored list
--install-rosettaInstall Rosetta 2 (Apple Silicon only)
--agree-to-licenseAuto-accept EULAs (required for Rosetta install)
--fetch-full-installerDownload a full macOS installer to /Applications
--full-installer-version VERSpecify which macOS version to fetch
--list-full-installersList available macOS installers
--backgroundTrigger a background scan/update (used by launchd)
`--schedule { onoff }`
--dump-stateDump the current update daemon state to log
-v, --verboseMore log detail

Listing pending updates

softwareupdate -l checks Apple's update servers, refreshes the local catalog, and prints anything available for installation. Output is two lines per item: a * Label: SOMETHING row and an indented descriptive Title: ... row. The label is the stable identifier you pass to --install, --ignore, and --download.

bash
softwareupdate -l

Output:

text
Software Update Tool

Finding available software
Software Update found the following new or updated software:
* Label: macOS Sequoia 15.5-24F74
	Title: macOS Sequoia 15.5, Version: 15.5, Size: 6489524KiB, Recommended: YES, Action: restart,
* Label: Command Line Tools beta 6 for Xcode-16.4
	Title: Command Line Tools beta 6 for Xcode, Version: 16.4, Size: 752856KiB, Recommended: NO,
* Label: Safari18.5MontereyAuto-18.5
	Title: Safari, Version: 18.5, Size: 156432KiB, Recommended: YES,

The asterisk-prefixed Label: line is what you pass to -i. Note the trailing version segment (-24F74, -16.4) — labels are version-specific so they change with every catalog refresh.

bash
# Just the labels, suitable for scripting
softwareupdate -l 2>/dev/null | awk -F': ' '/Label/ {print $2}'

Output:

text
macOS Sequoia 15.5-24F74
Command Line Tools beta 6 for Xcode-16.4
Safari18.5MontereyAuto-18.5
bash
# Recommended only — strip non-recommended from the dump
softwareupdate -l 2>/dev/null | awk '
    /Label:/  { lbl=$0 }
    /Recommended: YES/ { print lbl }
'

Output:

text
* Label: macOS Sequoia 15.5-24F74
* Label: Safari18.5MontereyAuto-18.5

The first softwareupdate -l after a reboot or after --reset-ignored can take 30–90 seconds. Subsequent runs use the cached catalog (--no-scan).

Installing updates

The install flow is "list → confirm → install". For routine maintenance, softwareupdate -ia -R is the workhorse: install everything available, restart automatically if any item requires it. The --restart flag is mandatory for OS updates that contain a kernel or firmware component; without it the install completes but pending work stays queued until the next manual reboot.

bash
# Install everything pending (security + recommended + optional)
sudo softwareupdate -ia

Output:

text
Software Update Tool

Downloading Safari
Downloaded Safari
Installing Safari
Done with Safari
Done.
bash
# Install everything AND restart if any update requires it
sudo softwareupdate -ia -R

Output:

text
Software Update Tool

Downloading macOS Sequoia 15.5
Downloaded macOS Sequoia 15.5
Installing macOS Sequoia 15.5
You need to restart your computer to install these updates.
The computer will restart automatically.
bash
# Only "recommended" — skip beta CLT, betas, optional firmware
sudo softwareupdate -i -r -R

Output:

text
Software Update Tool

Downloading Safari
Downloaded Safari
Installing Safari
Done with Safari
Done.
bash
# Install a specific update by label
sudo softwareupdate -i "Safari18.5MontereyAuto-18.5"

Output:

text
Software Update Tool

Downloading Safari
Downloaded Safari
Installing Safari
Done with Safari
Done.

[!WARN] The label string is case-sensitive, must include the trailing version segment, and must not include the leading * Label: prefix from softwareupdate -l. Quote it because labels often contain spaces and version dashes that the shell might misparse.

Download-only mode

softwareupdate -d LABEL (or --download --all) downloads the update payload to /Library/Updates/ without installing. Useful when you want to pre-stage a large macOS update during off-hours and install it later during a maintenance window.

bash
# Pre-stage all pending updates
sudo softwareupdate -d -a

Output:

text
Software Update Tool

Downloading macOS Sequoia 15.5
Downloading Safari
Done.
bash
# Where downloads land
ls -lh /Library/Updates/

Output:

text
total 0
drwxr-xr-x  4 root  wheel  128B May 25 10:02 071-12345
drwxr-xr-x  3 root  wheel   96B May 25 10:03 091-67890
bash
# Install from the cached download (no re-fetch)
sudo softwareupdate -i -a --no-scan -R

Output:

text
Software Update Tool

Installing macOS Sequoia 15.5
The computer will restart automatically.

Ignoring updates

--ignore LABEL adds an update to a system list that suppresses it from softwareupdate -l output and the System Settings notification badge. The list is per-system, stored in /Library/Preferences/com.apple.SoftwareUpdate.plist. Use this to defer a problematic update (e.g. an OS major version your enterprise hasn't certified) without disabling Software Update entirely.

bash
# Ignore the macOS 16 upgrade prompt
sudo softwareupdate --ignore "macOS Sequoia 15.5-24F74"
softwareupdate -l

Output:

text
Software Update Tool

Finding available software
Software Update found the following new or updated software:
* Label: Safari18.5MontereyAuto-18.5
	Title: Safari, Version: 18.5, Size: 156432KiB, Recommended: YES,
bash
# View the ignored list
defaults read /Library/Preferences/com.apple.SoftwareUpdate InactiveUpdates 2>/dev/null

Output:

text
(
    "macOS Sequoia 15.5-24F74"
)
bash
# Clear the ignored list — everything reappears
sudo softwareupdate --reset-ignored

Output:

text
Software Update Tool

Modern macOS (Big Sur 11+) restricts --ignore for major OS upgrades on Apple-Silicon Macs — Apple removed that affordance. It still works for point releases, Safari, Command Line Tools, and firmware. For full major-version blocking on managed fleets, use an MDM SoftwareUpdate payload.

Installing Rosetta 2

Rosetta 2 is Apple's x86_64-to-arm64 translation layer; first launch of an Intel-only binary on Apple Silicon triggers a GUI prompt, but the CLI install is the right step for unattended provisioning (CI runners, freshly imaged developer Macs, headless build hosts).

bash
# Install Rosetta 2 non-interactively
sudo softwareupdate --install-rosetta --agree-to-license

Output:

text
Software Update Tool

Finding available software
Installing: Rosetta 2
2025-05-25 10:30:00.123 softwareupdate[1234:5678] Package Authoring Error: Rosetta 2 will be installed.
Done with Rosetta 2
Done.
bash
# Verify Rosetta is installed by checking for the binary
ls -l /Library/Apple/usr/libexec/oah/translate

Output:

text
-rwxr-xr-x  1 root  wheel  98432 May 20 14:30 /Library/Apple/usr/libexec/oah/translate
bash
# Confirm an Intel binary now runs
arch -x86_64 uname -m

Output:

text
x86_64

[!WARN] --install-rosetta is a no-op on Intel Macs (it exits successfully with a "not needed" message). It only does meaningful work on Apple Silicon. Adding --agree-to-license is mandatory; without it the install pauses for an interactive EULA prompt that hangs in non-tty contexts.

Full installers — downloading the macOS installer app

For erasing and reinstalling a Mac (e.g. before resale, or to create a bootable installer USB), download the full installer app to /Applications and use it with createinstallmedia.

bash
# What macOS versions are available?
softwareupdate --list-full-installers

Output:

text
Software Update Tool

Finding available software
Software Update found the following full installers:
* Title: macOS Sequoia, Version: 15.5, Size: 14523432KiB, Build: 24F74
* Title: macOS Sequoia, Version: 15.4.1, Size: 14512345KiB, Build: 24E263
* Title: macOS Sonoma, Version: 14.7.5, Size: 13458912KiB, Build: 23H527
* Title: macOS Ventura, Version: 13.7.6, Size: 12345678KiB, Build: 22H626
bash
# Download the latest Sequoia installer (~14 GB)
sudo softwareupdate --fetch-full-installer --full-installer-version 15.5

Output:

text
Install finished successfully
bash
# Resulting installer
ls /Applications/ | grep "Install macOS"

Output:

text
Install macOS Sequoia.app
bash
# Create a bootable installer USB
sudo /Applications/Install\ macOS\ Sequoia.app/Contents/Resources/createinstallmedia \
    --volume /Volumes/USB --nointeraction

Output:

text
Erasing disk: 0%... 10%... 20%... 100%
Copying to disk: 0%... 100%
Making disk bootable...
Install media now available at "/Volumes/Install macOS Sequoia"

Background and scheduled updates

macOS runs softwareupdate --background periodically from a launchd timer (com.apple.softwareupdated.plist). You can toggle the whole feature with --schedule on/off and inspect the scheduler state via defaults read /Library/Preferences/com.apple.SoftwareUpdate.

bash
# Status of automatic updates
defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled
defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticDownload
defaults read /Library/Preferences/com.apple.SoftwareUpdate AutomaticallyInstallMacOSUpdates

Output:

text
1
1
0
bash
# Turn automatic checking on/off
sudo softwareupdate --schedule on
sudo softwareupdate --schedule off

Output:

text
Automatic check is on.
Automatic check is off.
bash
# Trigger an immediate background pass (used by launchd, but you can invoke it manually)
sudo softwareupdate --background

Output:

text
Software Update Tool

Background scan complete
bash
# Configure aggressive auto-update behaviour via defaults (then reboot)
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled    -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticDownload         -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticallyInstallMacOSUpdates -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate ConfigDataInstall         -bool true
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstall     -bool true

Output: (none — exits 0 on success)

Comparison vs mas and Homebrew

softwareupdate covers OS updates and Apple-shipped components only — macOS itself, Safari, Command Line Tools, XProtect, MRT, Gatekeeper signature bundles, Rosetta. It does not update third-party CLI tools (ripgrep, node) or App Store apps (Pages, Xcode). For complete fleet automation you need three tools, each with a specific scope.

ToolScopeInstallTypical usage
softwareupdatemacOS itself, Safari, CLT, XProtect, firmware, Rosettabuilt-insudo softwareupdate -ia -R
masMac App Store apps (Pages, Xcode, Keynote, Slack-from-MAS)brew install masmas upgrade
brewHomebrew formulae + casks (CLI + non-MAS GUI apps)/bin/bash -c "$(curl ...)"brew update && brew upgrade && brew upgrade --cask
bash
# Install mas if you don't have it
brew install mas

# List outdated Mac App Store apps
mas outdated

Output:

text
409183694 Keynote (14.0)
408981434 iMovie (10.4.2)
640199958 Apple Developer (12.1)
bash
# Upgrade everything in the App Store
mas upgrade

Output:

text
==> Upgrading 3 outdated applications:
Keynote (14.0), iMovie (10.4.2), Apple Developer (12.1)
==> Downloading Keynote
==> Installed Keynote
...
bash
# Compare: brew side
brew update
brew outdated
brew upgrade
brew upgrade --cask
brew cleanup

Output:

text
==> Auto-updated Homebrew!
==> Outdated Formulae
ripgrep 14.1.0 -> 14.1.1
node    20.12.0 -> 20.14.0
==> Upgrading 2 outdated packages:
ripgrep 14.1.0 -> 14.1.1
node    20.12.0 -> 20.14.0

A complete "Update Everything" sequence is sudo softwareupdate -ia && brew update && brew upgrade && brew upgrade --cask && mas upgrade. Wrap in a single script and you have a one-command Mac maintenance routine.

Command Line Tools — installation paths

The Apple Command Line Tools (CLT) bundle (clang, git, make, headers) is also distributed via softwareupdate. There are three ways to install it.

bash
# Method 1: xcode-select triggers an interactive popup
xcode-select --install

Output: (none — exits 0 on success; shows a GUI prompt)

bash
# Method 2: softwareupdate, scriptable
# Step 1 — create the marker file softwareupdate uses to enable CLT in its listing
sudo touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress

# Step 2 — find and install the latest CLT label
PROD=$(softwareupdate -l 2>&1 | awk '/Command Line Tools/ {sub(/^\* Label: /,""); print; exit}')
sudo softwareupdate -i "$PROD"

# Step 3 — remove the marker
sudo rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress

# Verify
xcode-select -p

Output:

text
/Library/Developer/CommandLineTools
bash
# Method 3: Full Xcode from the App Store (`mas install 497799835`) — also provides CLT
mas install 497799835

Output: (none — exits 0 on success)

Reading the update log

softwareupdate writes detailed activity to /var/log/install.log (install events) and to the unified system log under subsystem com.apple.SoftwareUpdate. For troubleshooting a stuck or failed update, both are essential.

bash
# Recent install.log entries
sudo tail -50 /var/log/install.log

Output:

text
2026-05-25 10:30:00+0000 myhost softwareupdated[123]: SUTool: Available updates pre-flight=0 actually=2
2026-05-25 10:30:15+0000 myhost softwareupdated[123]: SUTool: Installing Safari18.5
2026-05-25 10:30:45+0000 myhost installd[456]: PackageKit: package install: stage success
2026-05-25 10:31:02+0000 myhost softwareupdated[123]: SUTool: Done with Safari18.5
bash
# Stream live unified-log events from softwareupdated
log stream --predicate 'subsystem == "com.apple.SoftwareUpdate"' --level debug

Output: (streams continuously until Ctrl-C)

text
2026-05-25 10:30:00.123  softwareupdated  [DEBUG] Beginning background scan
2026-05-25 10:30:01.456  softwareupdated  [DEBUG] Catalog refreshed: 3 items
2026-05-25 10:30:02.789  softwareupdated  [DEFAULT] Notification posted for available updates
bash
# Historical log query — last 24 hours of softwareupdate activity
log show --predicate 'subsystem == "com.apple.SoftwareUpdate"' --last 24h --info

Output: (multi-page tabular log dump — pipe to less or grep to scope)

Common pitfalls

  1. Forgetting sudosoftwareupdate -ia without sudo exits silently with no installs done. Always prefix install ops with sudo.
  2. Quoting labels wrong — labels contain spaces, dashes, and digits. Use single quotes: sudo softwareupdate -i 'macOS Sequoia 15.5-24F74'.
  3. Major OS upgrades no longer install non-interactively — since Big Sur, upgrading to a new major macOS version via softwareupdate -i is blocked on Apple Silicon. Use --fetch-full-installer plus startosinstall, or use an MDM-pushed update.
  4. -R without battery — on a laptop, --restart triggers an immediate reboot. If you're on battery and below 50%, the install daemon refuses to start the OS update; check pmset -g batt before scheduling.
  5. Rosetta install fails silently on Intel--install-rosetta is a no-op on Intel; check uname -m first.
  6. Pre-staged downloads expire — items in /Library/Updates/ can be invalidated when the catalog refreshes. Use --no-scan to install from the cache without a fresh check, but only within ~24 hours of the download.
  7. --list returns stale datasoftwareupdate -l --no-scan uses cache that may be hours old. Force-refresh: sudo softwareupdate --background followed by softwareupdate -l.
  8. MDM-managed Macs override CLI choices — if a Jamf/Mosyle/Kandji profile restricts updates, your --install / --ignore operations may be silently no-ops. Check profiles -P.
  9. FileVault delays restart — if FileVault is enabled, -R schedules the restart but the system asks for credentials on the next boot. Headless servers should use fdesetup authrestart (provide unlock credentials in advance).
  10. --ignore doesn't block silent installs — Apple-pushed XProtect, MRT, and Gatekeeper signature bundles install via softwareupdated regardless of the ignore list. To suppress those, disable ConfigDataInstall and CriticalUpdateInstall in the preferences plist — at your own risk.
  11. Stale softwareupdated cache — if softwareupdate -l shows the same update for days after you installed it, kill the daemon: sudo killall softwareupdated. It will respawn from launchd within seconds.
  12. CLT label changes with each Xcode beta — automation that hardcodes a label like Command Line Tools for Xcode-16.3 breaks at Xcode 16.4. Always parse the latest label out of softwareupdate -l.

Real-world recipes

One-shot "patch everything, restart if needed"

The single-command system update used for maintenance windows.

bash
sudo softwareupdate -ia -R --no-scan

Output:

text
Software Update Tool

Downloading Safari
Downloaded Safari
Installing Safari
Done with Safari
Done.

Update macOS + Homebrew + App Store in one script

A complete maintenance routine. Run weekly.

bash
#!/bin/bash
# update-everything.sh — patch macOS, Homebrew, and App Store apps
set -euo pipefail
log()  { echo "[$(date +%H:%M:%S)] $*"; }

log "Apple updates"
sudo softwareupdate -ia -R --no-scan || log "softwareupdate had issues"

log "Homebrew formulae"
brew update
brew upgrade
brew cleanup -s

log "Homebrew casks"
brew upgrade --cask --greedy

log "Mac App Store"
if command -v mas >/dev/null; then
    mas upgrade
fi

log "Done"

Output:

text
[10:30:01] Apple updates
[10:35:42] Homebrew formulae
==> Upgrading 5 outdated packages...
[10:38:11] Homebrew casks
[10:40:22] Mac App Store
[10:41:05] Done

Provision a fresh Apple Silicon Mac

After unboxing an M-series Mac, run this once to install Rosetta, CLT, and update everything.

bash
#!/bin/bash
set -euo pipefail

# Rosetta 2 (for Intel binaries; needed by some Homebrew bottles)
if [[ "$(uname -m)" == "arm64" ]]; then
    sudo softwareupdate --install-rosetta --agree-to-license
fi

# Command Line Tools (clang, git, make, headers)
if ! xcode-select -p >/dev/null 2>&1; then
    sudo touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
    CLT=$(softwareupdate -l 2>&1 | awk '/Command Line Tools/ {sub(/^\* Label: /,""); print; exit}')
    sudo softwareupdate -i "$CLT" --verbose
    sudo rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
fi

# OS updates
sudo softwareupdate -ia

# Homebrew
if ! command -v brew >/dev/null; then
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi

echo "Bootstrap complete. Reboot when convenient."

Output:

text
Software Update Tool

Installing: Rosetta 2
Done with Rosetta 2
Done.
Software Update Tool

Downloading Command Line Tools for Xcode
Done.
==> Now run brew update && brew bundle to install your packages
Bootstrap complete. Reboot when convenient.

Defer the next major OS upgrade

Block the macOS 16 nag without disabling Software Update.

bash
sudo softwareupdate --ignore "macOS Sequoia 16.0-25A123"
softwareupdate -l

Output:

text
Software Update Tool

Finding available software
No new software available.

(Replace the label with whatever softwareupdate -l actually shows.)

Audit pending updates across a fleet via SSH

A one-liner pattern for inventorying outstanding patches.

bash
for host in mac01 mac02 mac03 mac04; do
    printf "%-12s " "$host"
    ssh "$host" 'softwareupdate -l 2>/dev/null | grep -c "^* Label:"'
done

Output:

text
mac01        2
mac02        0
mac03        5
mac04        1
bash
# Or detailed: every host's pending labels
for host in mac01 mac02 mac03 mac04; do
    echo "=== $host ==="
    ssh "$host" 'softwareupdate -l 2>/dev/null | grep "^\* Label:"'
done

Output:

text
=== mac01 ===
* Label: Safari18.5MontereyAuto-18.5
* Label: macOS Sequoia 15.5-24F74
=== mac02 ===
=== mac03 ===
* Label: macOS Sequoia 15.5-24F74
* Label: Safari18.5MontereyAuto-18.5
* Label: XProtectPayloads_10_15-100
* Label: XProtectPlistConfigData_10_15-2186
* Label: Command Line Tools for Xcode-16.4

Create a bootable Sequoia installer USB

For tech-bench reinstall scenarios.

bash
# 1. Fetch the full installer (~14 GB)
sudo softwareupdate --fetch-full-installer --full-installer-version 15.5

# 2. Format the target USB stick
diskutil eraseDisk JHFS+ "MacInstall" /dev/disk4

# 3. Build the bootable media
sudo /Applications/Install\ macOS\ Sequoia.app/Contents/Resources/createinstallmedia \
    --volume /Volumes/MacInstall --nointeraction

Output:

text
Erasing disk: 0%... 10%... 20%... 100%
Making disk bootable...
Install media now available at "/Volumes/Install macOS Sequoia"

Schedule overnight downloads, install on demand

Pre-stage during the night, install during a controlled morning window.

bash
# 11pm — schedule via cron or a launchd plist
sudo softwareupdate -d -a --no-scan

# Morning maintenance window — install from cache
sudo softwareupdate -ia --no-scan -R

Output: (none — see install.log for detail)

Block all auto-update behaviour

For an air-gapped build host where you control every install manually.

bash
sudo softwareupdate --schedule off
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled     -bool false
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticDownload          -bool false
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticallyInstallMacOSUpdates -bool false
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate ConfigDataInstall          -bool false
sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate CriticalUpdateInstall      -bool false

Output: (none — exits 0 on success)

[!WARN] Disabling ConfigDataInstall and CriticalUpdateInstall blocks the silent XProtect / MRT signature bundles that protect against new malware families. Only do this on intentionally isolated hosts where you accept the trade-off.

Send a Slack ping when updates are available

Wire softwareupdate -l into a daily notification.

bash
#!/bin/bash
# check-updates-and-notify.sh
COUNT=$(softwareupdate -l 2>/dev/null | grep -c "^\* Label:")
if (( COUNT > 0 )); then
    LABELS=$(softwareupdate -l 2>/dev/null | grep "^\* Label:" | sed 's/^\* Label: /  • /')
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\": \"*${HOSTNAME}* has $COUNT pending update(s):\n\`\`\`\n$LABELS\n\`\`\`\"}" \
        "$SLACK_WEBHOOK_URL"
fi

Output: (none — webhook fires)

Schedule the script above as a daily launchd StartCalendarInterval agent under ~/Library/LaunchAgents/. See launchctl for the plist skeleton.

See also

  • homebrew — third-party CLI and GUI package management.
  • macos-cli — broader macOS terminal reference.
  • xattr — clearing quarantine on downloaded installers before installer -pkg.
  • masbrew install mas for App Store CLI; pairs with softwareupdate and brew for full fleet update coverage.

Sources

References consulted while writing and updating this article. Links open in a new tab. Order is curated by relevance — sorting is intentionally disabled (data-no-sort).

SourceWhy cited
What's new for enterprise in macOS Tahoe 26 — Apple SupportAuthoritative announcement that the MDM com.apple.SoftwareUpdate payload and related commands are deprecated and slated for removal in the next major macOS, motivating the Declarative-Software-Update WARN callout.
How macOS 26 Tahoe updates: 3 Catalogues — Eclectic Light Co.Detailed trace of the softwareupdated catalog flow (Pallas server, macOS26Short / macOS26Long delta vs. full update, mobile-asset catalogs) underpinning the install-internals section.
How macOS 26 Tahoe updates: 4 Download, preparation, installation — Eclectic Light Co.Preflight / cryptex / RecoveryOS phase walkthrough used to validate the modern restart-and-stage flow described in Installing updates.
Update macOS on Mac — Apple SupportCanonical user-facing Apple documentation cross-referenced for terminology (recommended vs. optional, point release vs. major upgrade) used in Listing pending updates and Installing updates.
The Software Update UI for Upgrading to macOS 26 Tahoe Is Needlessly Confusing — Daring FireballIndependent commentary on the Tahoe upgrade UX confirming the recommendation to pin labels parsed at runtime rather than hard-coded.
mas-cli/mas on GitHubAuthoritative reference for the App Store CLI used in the "Update macOS + Homebrew + App Store in one script" recipe.