brew-cask-upgrade: upgrading Homebrew casks with per-app control
A command line tool for upgrading every outdated app installed by Homebrew Cask
At a glance
- What is it?
- brew-cask-upgrade is an external Homebrew command that upgrades outdated GUI apps installed as casks, with per-app prompts, glob patterns and version pinning. It is a small Ruby tap layered on top of Homebrew rather than a replacement for it.
- Who is it for?
- Adopt brew-cask-upgrade if you install GUI apps through Homebrew Cask and want per-app control, glob targeting or pinning that the native upgrade path does not offer. Skip it if you rely on each app's own updater, or if you want a single upgrade command for both formulae and casks: this tool only covers casks, and it will not touch apps that auto-update unless you pass -a.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 26 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What brew-cask-upgrade replaces, and for whom
Homebrew Cask installs macOS GUI applications and large binaries through Homebrew. The native upgrade path treats those apps as one batch. brew-cask-upgrade, invoked as brew cu, is an external command that the README describes as a replacement for the native upgrade, offering interactivity, an improved interface and higher granularity of what to upgrade.
The audience is narrow and specific: people who already manage apps with Homebrew Cask and who are annoyed by all-or-nothing upgrades. If you install apps by dragging them into /Applications, this tool has nothing to offer. It only knows about casks that Homebrew tracks. The value shows up when a batch upgrade would touch an app you deliberately keep on an older version, or when you want to see what will change before it changes.
How brew cu decides what to upgrade
The command runs as a Homebrew external command, which is why the tap name matters: Homebrew resolves brew cu by looking for a cu executable inside the tapped repository. The repository layout reflects this, with bin/, cmd/ and lib/ directories alongside the gemspec and the README.
By default, running brew cu without further options automatically runs brew update first, to get the latest versions of the installed casks. That behaviour is documented as disableable through the --no-brew-update option. The tool then compares installed casks against the available versions and upgrades the outdated ones.
Two filtering rules shape the result. Apps with their own auto-update functionality are skipped and reported with a PASS result, unless you pass -a or --all. And apps marked as latest are skipped unless you pass -f or --force, which force-reinstalls them. The README also notes a consequence worth reading twice: if you let an app update itself, that change is not reflected in brew cu, and the tracked version only moves when the app is upgraded through brew cu --all.
Installing the tap and running a first upgrade
Installation is a single tap command. After it, Homebrew knows about the external command.
brew tap buo/cask-upgradeTo confirm the tap registered, run brew tap and look for buo/cask-upgrade in the list. The README shows exactly that check, with the tap appearing alongside homebrew/bundle, homebrew/cask and homebrew/core.
brew tapA first real run is just the command name. The README states that this form automatically runs brew update before checking outdated apps, so expect a pause while Homebrew refreshes itself.
brew cuIf you would rather approve each app, add the interactive flag. Per cask you then answer y to install the update, N to skip it, or p to pin the current version.
brew cu --interactiveTo target a subset instead, pass a quoted glob pattern. Quoting matters: the README warns that an unquoted pattern is expanded by the shell before brew ever sees it.
brew cu 'firefox*'Glob patterns, pinning, and the quoting trap
The pattern support is the part most likely to bite. Three forms are documented: * matches any characters, ? matches a single character, and [abc] matches any character inside the brackets. So brew cu 'flash-*' upgrades every cask whose name starts with flash-, and brew cu 'app[123]' matches app1, app2 and app3.
The failure mode is shell expansion, not the tool. If you type brew cu firefox* without quotes, your shell expands the pattern against files in the current directory first, and whatever survives is what brew receives. The README offers three correct forms: quote it, escape the asterisk as firefox\*, or use noglob brew cu firefox* in zsh.
Pinning is the other control surface. brew cu pin freezes the current version so brew cu leaves it alone; unpin releases it, and pinned prints the pinned apps and versions. One caveat is stated plainly: pinning inside brew cu does not stop brew cask upgrade from updating pinned apps. The pin is a brew-cask-upgrade concept, not a Homebrew-wide lock.
Pinned state can also be exported and reloaded. brew cu pinned --export my-backup-filename.txt writes a file, and --load reads it back. Versions are not exported, because the README says it is not possible to install a specific version afterwards. Loading replaces the current pinned set rather than merging with it.
The Mac App Store flag is experimental, and the README says so
Passing --include-mas pulls Mac App Store applications into the same run by delegating to the mas CLI tool. The README labels this feature experimental and states that functionality is not guaranteed, with use at your own risk. That is an unusually direct disclaimer for a README, and it should be read as a scope boundary rather than boilerplate.
The practical consequence is that a mixed run of casks and App Store apps has one well-supported half and one unsupported half. If something goes wrong with an App Store upgrade, the tool's own documentation has already disclaimed it. Treat --include-mas as a convenience for people who already use mas and accept the risk, not as a reason to choose this tool.
The auto-update exclusion is the other limitation worth naming. Many modern macOS apps ship their own updater. brew cu skips them by default and reports PASS, which is correct behaviour but also means the tool's picture of your system can drift from reality: an app that updated itself still shows its old tracked version until you run brew cu --all.
Where it sits next to plain Homebrew and topgrade
The direct alternative is Homebrew itself. Native cask upgrading is a single command with no per-app prompt, no glob targeting and no pinning layer. If that is enough for you, adding a tap adds a dependency you do not need. brew-cask-upgrade exists precisely because that is not enough for some people, and the README frames the project that way: a replacement offering interactivity and granularity.
A different kind of alternative is a general system-upgrade runner such as topgrade, which orchestrates many package managers and tools behind one command. The difference in approach is direction. brew-cask-upgrade goes deep on one ecosystem, Homebrew Cask, and adds controls inside it: pinning, globs, interactive per-cask decisions, export and import of pinned state. A multi-manager runner goes wide, calling each tool's own upgrade path in turn. If your problem is remembering to run five different updaters, brew-cask-upgrade is the wrong shape. If your problem is that Homebrew Cask upgrades your GUI apps as an undifferentiated batch, it is the right one.
Note also what brew-cask-upgrade does not manage: Homebrew formulae. It is a cask tool, and the README's scope stays there.
Maintenance, licence, and what upgrading costs you
The repository is not archived, and the last push was on 2026-09-04. It carries a CI workflow under .github/, and the README opens with that badge. The project is MIT licensed, which permits commercial and private use, modification and redistribution provided the copyright notice and permission notice are retained. That is a permissive licence, but it is not legal advice and says nothing about the licences of the apps you install through Homebrew Cask.
Upgrade cost for the tool itself is low, because a tap is just a Git checkout: brew update refreshes it along with everything else, and brew untap buo/cask-upgrade removes it. The README does not document a version-to-version migration path, so there is no upgrade procedure to plan around. The real cost is operational: every brew cu run that does not pass --no-brew-update triggers a Homebrew self-update first, which is slower than a bare upgrade and can surprise you in a script. The --cleanup flag exists for the other side of that cost, cleaning cached downloads and tracker symlinks after updating.
Editorial conclusion
Adopt brew-cask-upgrade if you install GUI apps through Homebrew Cask and want per-app control, glob targeting or pinning that the native upgrade path does not offer. Skip it if you rely on each app's own updater, or if you want a single upgrade command for both formulae and casks: this tool only covers casks, and it will not touch apps that auto-update unless you pass -a. Before trusting it, run brew tap, then brew cu -i on a machine where you can afford to reinstall a cask or two.
Frequently asked questions
What does cask mean in Homebrew?
In this project's context, a cask is a macOS GUI application or large binary managed by Homebrew Cask, which extends Homebrew to install and manage those applications. brew-cask-upgrade operates on casks, not on formulae.
How do I install brew-cask-upgrade using brew?
Run brew tap buo/cask-upgrade. The README suggests verifying it with brew tap and checking that buo/cask-upgrade appears in the output.
How can I update Homebrew on my Mac with brew-cask-upgrade?
Running brew cu without extra options automatically runs brew update to fetch the latest versions of installed casks. You can suppress that with the --no-brew-update option.
How to auto update brew?
The README does not document an automatic scheduling mechanism for brew cu itself. What it does document is that brew cu runs brew update before checking outdated apps unless --no-brew-update is passed, and that apps with their own auto-update functionality are skipped unless -a or --all is used.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/buo-homebrew-cask-upgrade)