Casks and formulae: the one-paragraph version
Homebrew manages two kinds of software. Formulae are command-line tools and libraries — git, ffmpeg, node — that Homebrew builds or unpacks into its own prefix. Casks are prebuilt GUI apps — browsers, editors, chat clients — that Homebrew fetches from the vendor's official release URL and places in /Applications. The split matters for updates: upgrading a formula swaps files inside Homebrew's directory, while upgrading a cask replaces an app bundle in place, which is closer to an automated reinstall than a package update. Everything below is about casks, since those are the double-clickable apps you see in your Dock and Applications folder.
The core cask update workflow
Four commands cover almost all day-to-day cask maintenance. Refresh Homebrew's index first, then see what it manages and what is behind:
brew update
brew list --cask
brew outdated --cask
brew outdated --cask compares each installed cask's recorded version against the current index. Before upgrading anything unfamiliar, inspect it:
brew info --cask <token>
brew info shows the version you would get, the vendor URL it comes from, and flags like auto_updates that change upgrade behavior. Then upgrade one app by its token, or omit the token to take every outdated cask at once:
brew upgrade --cask <token>
brew upgrade --cask
Upgrading one token at a time is slower, but it gives you a chance to notice a major-version jump before it happens — more on that below.
The auto_updates problem: why brew says Chrome is fine
Run brew outdated --cask on a Mac with Chrome installed and Chrome will almost never appear, even when a new version shipped yesterday. That is by design. Many casks are marked auto_updates because the app updates itself — Chrome, Edge, Zoom, and most Electron apps fall in this group. Others use version :latest because the vendor publishes a single unversioned URL, so Homebrew has no version numbers to compare. brew outdated and brew upgrade skip both kinds by default.
The --greedy flag includes them:
brew outdated --cask --greedy
brew upgrade --cask --greedy
Understand what you are signing up for. For version :latest casks, --greedy reinstalls every time, because Homebrew cannot tell whether your copy is current. For auto_updates apps that already updated themselves, Homebrew's recorded version is stale, so --greedy can re-download an app that is already newer than what the cask index knows. If you want finer control, --greedy-auto-updates and --greedy-latest target each group separately.
Avoiding surprise major versions
brew pin holds a formula at its current version, but pinning does not exist for casks. If a blanket brew upgrade --cask runs, every outdated cask moves to whatever the index says is current — including paid major upgrades and redesigns you did not ask for. Three habits keep that under control:
- Upgrade by token instead of running a blanket brew upgrade --cask, and check brew info --cask first to see how big the version jump is.
- Use a versioned cask where one exists (for example firefox@esr or temurin@17) so the token itself tracks the release stream you want.
- Back up the current app bundle before a big jump. Homebrew does not keep the old version, so there is no brew-native rollback for casks.
The backup guide covers a simple copy-aside routine that makes any cask upgrade reversible.
When a cask upgrade can't work
Sometimes brew upgrade fails or does something unexpected, and the cause is usually one of a few known situations:
- You moved or renamed the app. Homebrew expects the bundle where the cask installed it; a moved app can be skipped or reinstalled as a second copy.
- The cask is deprecated or disabled. Vendors change how they distribute apps, and brew info --cask shows the deprecation notice and the reason.
- The app was installed manually, not through Homebrew. A matching cask in the index does not mean brew owns your copy — it only manages what it installed.
For the last case, newer Homebrew releases can adopt an existing app with brew install --cask --adopt <token>, as long as the installed version matches the cask. When no cask path works, fall back to the vendor's own release: get the new build from the official site, verify it with spctl -a -vv before first launch, and keep the old bundle until the new one runs cleanly.
Where macCurrent fits alongside Homebrew
Homebrew is excellent at what it manages, but it only sees apps installed through Homebrew. App Store apps, Sparkle-updating apps, vendor-managed suites, and manual installs live outside brew list --cask entirely — the guide to Mac app update sources maps the full landscape.
macCurrent shows your cask-managed apps in the same list as everything else, labeled by source, so you can see at a glance which apps brew covers and which it cannot. When a cask cannot cleanly upgrade an app — it is marked auto_updates, the cask is deprecated, or your copy was installed manually — macCurrent flags it and points at the path that will work, showing the signing identity and version direction before anything changes. The pillar guide to updating Mac apps safely explains those review checks in detail. macCurrent is a free beta delivered as one universal app for Apple silicon and Intel Macs on macOS 15 or later: install macCurrent and see which of your apps Homebrew actually covers.
Frequently asked questions
Does Homebrew update App Store apps?
No. Homebrew manages formulae and casks installed through Homebrew. App Store apps update through Apple's App Store, and Homebrew has no visibility into them.
Why doesn't brew outdated --cask show an app I know is out of date?
The cask is probably marked auto_updates or version :latest, both of which brew outdated skips by default. Run brew outdated --cask --greedy to include them, keeping in mind that Homebrew's recorded version may be stale for apps that update themselves.
What does brew upgrade --cask --greedy actually do?
It includes casks that brew normally skips: apps marked auto_updates and casks pinned to version :latest. For :latest casks it reinstalls every time because there is no version to compare, and for auto_updates apps it may re-download an app that already updated itself past the cask index's version.
Can I pin a cask to a specific version?
No. brew pin only works for formulae. To stay on an older stream, use a versioned cask such as firefox@esr where one exists, upgrade casks individually by token instead of all at once, and keep a backup of the current bundle, since Homebrew offers no rollback for casks.
Should I use Homebrew or macCurrent?
They solve different parts of the problem. Homebrew installs and upgrades Homebrew-managed software; macCurrent shows update status across every source — Homebrew, the App Store, Sparkle, vendor updaters, and direct downloads — and flags the apps Homebrew cannot cleanly upgrade.