CLI tool
Homebrew/BrewUI avatar
Homebrew/BrewUI

BrewUI: Homebrew's own macOS GUI, and what it does not wrap

📺 Homebrew's official macOS GUI

2,333 stars73 forksSwiftAGPL-3.0

At a glance

What is it?
An official SwiftUI front end for the brew CLI, distributed as a cask, with a localization system and a lint gate that blocks commits. It renders Homebrew rather than replacing it.
Who is it for?
BrewUI earns the official designation by not doing anything clever underneath. It reads from the brew CLI and the Homebrew JSON API, it installs as a cask through Homebrew itself, and it makes no attempt to be a package manager with a different opinion.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A SwiftUI window over the brew command line

The stated motivation is narrow: enable users who prefer graphical interfaces to discover, install, update and manage Homebrew packages safely, through a native SwiftUI interface that never hides what Homebrew is doing. That last clause is the design constraint that explains most of the project's decisions.

What BrewUI is not is a new package manager. The README says its data comes from the brew CLI and the Homebrew JSON API at formulae.brew.sh, and the motivation says it maintains complete transparency about underlying Homebrew operations. So the app is a rendering layer. Packages, casks and formulae are still resolved by Homebrew, in Homebrew's order, with Homebrew's rules, and the interface is a different way of reaching the same result.

The stack is plain and modern: Swift with strict concurrency, SwiftUI, and Swift Package Manager. Toolchain and macOS requirements are pinned in files rather than described in prose, in Package.swift, a .swift-version file and the Homebrew.xcodeproj project file. Repository topics are empty, but the tree describes the structure: a Homebrew directory for the app target, a Sources directory holding the feature packages, BrewTests and BrewUITests for the two test suites, three separate xctestplan files for unit, UI and end-to-end runs, plus Tools and scripts directories.

The license is AGPL-3.0, and the README is explicit that reusing or adapting the source brings the AGPL terms with it, including the network-use clause. For a GUI that talks to a local service on the same machine, that clause matters more than it would for a command line tool.

Installing as a cask and configuring through brew.env

The install instruction is one line, and it is Homebrew installing itself:

bash
brew install --cask homebrew-app

Distributing a GUI through the package manager it fronts is the detail worth pausing on. It means the app arrives signed, versioned and updatable through the same channel as everything else on the machine, with no separate download page and no second update mechanism.

Configuration has one rule that will trip up anyone used to shell customization. Homebrew options go in a file called `brew.env`, and BrewUI must be relaunched for a change to take effect. The README states plainly that shell aliases and exported variables do not configure the app. That is not an oversight; it is the consequence of the app not inheriting your interactive shell environment. If you have been relying on an alias, a PATH export or a shell function to shape how brew behaves, BrewUI will not see it, and the `brew.env` file is where that intent has to be restated.

The release history shows one related fix worth noting. v0.4.3 included a change to include Homebrew's sbin directory in the shell PATH, contributed by MikeMcQuaid. That is the kind of bug that only shows up on a machine where Homebrew was installed somewhere the GUI did not expect.

What the release notes reveal about actual behavior

The releases are version 0.x and dated weekly, which tells you this is a young project iterating in public. v0.4.2 came on 2026-09-15, v0.4.3 on 2026-09-17 and v0.4.4 on 2026-09-22, with the repository's last push on 2026-09-28.

Most of the changes are the small behavioral details that separate a usable app from a demo. v0.4.4 added a deprecated badge on installed formulae, kept list position after uninstalling something, filtered installed dependencies out of the installed list, and added the localization system together with an alternative English dialect. v0.4.3 dropped the leading icon from package list rows, fixed the window size, linted the app in CI and fixed stale paths.

Two of these deserve more attention than they were given. Keeping list position after an uninstall is the kind of thing you only notice when it is missing, since a list that jumps under your cursor while you are clicking through packages is genuinely irritating. And the deprecated badge is a correctness feature, because a formula that upstream has marked deprecated is something you want to see before it breaks, not discover from an error message.

The project also tightened its own contribution process during this period. v0.4.2 added and enforced issue and pull request templates, required before and after screenshots in pull requests, and ran Homebrew through an isolated zsh. Enforcing screenshots is a strong convention for a GUI project, since it makes visual regressions reviewable in the pull request itself rather than after merge.

Several first-time contributors appear across these three releases, including gyanu2507, rajin-khan, bevanjkay, SurefireStudios and luckman212. A repository run by BrewTestBot for shared configuration synchronization alongside named human contributors is a healthy pattern.

The commit hook is a real quality gate

Development setup is a single script:

bash
./scripts/bootstrap

What that script does is more interesting than the command. It installs Mint from the Brewfile, runs `mint bootstrap` to build the exact SwiftFormat and SwiftLint versions pinned in the Mintfile, enables the repository git hooks, and resolves Swift package dependencies for the Xcode project. Pinning the linters themselves through Mintfile is the detail that makes the gate trustworthy, since a linter upgrade cannot silently change what a commit accepts.

After bootstrap, commits run checks on staged Swift files, in order: formatting, then linting with `--fix` followed by strict validation. The hook also runs BrewUILint over the production tree, and if unresolved violations remain the commit is blocked, with the failures printed so you can fix and re-commit. So there are three distinct gates, and the third one is project-specific rather than a generic linter.

The tree backs up that claim. There is a .swiftformat config, a .swiftlint.yml, a .periphery.yml for unused code detection, a Mintfile, a Brewfile and a CLAUDE.md next to AGENTS.md. Release v0.4.3 moved app linting into CI as well, so the checks are not only local.

The consequence for a contributor is that a rejected commit here usually means a formatting or lint violation with a named rule, not an unexplained failure. That is a better experience than most Swift packages offer.

Localization treated as an architecture concern

The translations section is the longest part of the README, which is unusual and turns out to be justified. The system uses one Localizable.xcstrings catalog per UI target: one for the window, sidebar and menus under the Homebrew directory, and one in Resources inside BrewUIComponents and each BrewFeature package.

Two constraints are documented because violating them produces silent breakage. First, an empty translation renders as empty text rather than falling back to English, so a partial contribution means deleting the entry rather than clearing it. Second, a language that exists only in a package catalog never loads, because macOS only lists a language in the per-app picker when the app bundle ships it. That is why adding a language means opening the main catalog, translating at least one string, and committing the knownRegions change in the Xcode project.

Plural handling is where most projects get this wrong, so the README is specific. English needs only two plural forms, so the code picks between two keys itself, `1 package` and `%lld packages`. A language with more plural categories varies the numeric key by plural rule in Xcode and translates the singular key as well. Format specifiers must be preserved and can be renumbered, for example `%1$@` and `%2$lld`, when a language needs a different order, and nothing checks that for you.

The tooling around it is minimal and explicit:

bash
scripts/localize verify
scripts/localize status
scripts/localize sync

`verify` gates on blanks and on catalogs that drifted from the built sources, `status` reports progress per language, and `sync` runs automatically as part of an Xcode build. When English copy changes, sync adds the new key and marks the old one stale while keeping its translations, so a reworded string does not lose the languages that already translated it. None of this is clever, and all of it is the difference between a translated app and an English app with translation scaffolding.

Where a GUI over brew is the wrong tool

The honest limitation is the one the project states about itself, and it is a real one. A GUI is good at discovery, at seeing what is installed, and at the two operations everyone performs: installing something and updating everything. It is bad at everything Homebrew is actually good at.

A brew command composes. You can install a package with a specific flag, pin a version, tap a repository, work through a bulk operation, or pipe output into something else. None of that is a click sequence, and a GUI has no equivalent of shell composition, which means the awkward cases still belong in the terminal.

There is a second constraint that follows from the design. Because the app reads from the brew CLI and the JSON API rather than owning state, anything the CLI cannot report is something the app cannot show. The deprecated badge added in v0.4.4 is a good example of the pattern working in your favour: the information came from Homebrew and the app surfaced it. Equally, there is no route for the app to show something Homebrew does not know.

And the status line is worth repeating as a fact rather than a claim. The README says stable and under active development, at version 0.4.4 with AGPL-3.0 licensing. A 0.x version with weekly releases means the interface can still change, which is fine for an app you use but worth knowing if you were planning to script around it.

Editorial conclusion

BrewUI earns the official designation by not doing anything clever underneath. It reads from the brew CLI and the Homebrew JSON API, it installs as a cask through Homebrew itself, and it makes no attempt to be a package manager with a different opinion. For someone who wants a Mac interface over the tools they already use from a terminal, that is exactly the right design, and the release history shows small honest fixes such as keeping list position after an uninstall and marking deprecated formulae. What you give up by using it is speed and flexibility: a real brew command composes, and a click sequence does not. Install it with `brew install --cask homebrew-app`, put any Homebrew options in `brew.env` rather than a shell alias, and keep the terminal open for anything the app does not surface.

Frequently asked questions

Is there a Homebrew GUI available for Mac?

Yes. BrewUI is Homebrew's official macOS GUI, written in SwiftUI and distributed through Homebrew itself with `brew install --cask homebrew-app`. It reads from the brew CLI and the Homebrew JSON API, so it renders what Homebrew does rather than implementing its own package management.

How do I configure Homebrew options for the BrewUI app?

Put them in a file called brew.env and relaunch BrewUI afterwards. The README is explicit that shell aliases and exported variables do not configure the app, because it does not inherit your interactive shell environment. Any option you normally set through an alias or an export has to be restated in brew.env.

What is the license on BrewUI and can I reuse its source?

BrewUI is licensed AGPL-3.0, and the README states that if you reuse or adapt the source the AGPL terms apply, including the network-use clause. That clause is the part to consider if you plan to base another project on it, since it reaches network use rather than only redistribution.

How do I set up a development environment for BrewUI?

Clone the repository and run ./scripts/bootstrap. That installs Mint from the Brewfile, runs mint bootstrap to build the SwiftFormat and SwiftLint versions pinned in the Mintfile, enables the repository git hooks and resolves Swift package dependencies. After that, commits automatically run formatting, linting with fix, and a BrewUILint pass over the production tree that blocks the commit if violations remain.

Official sources

  1. Homebrew/BrewUI on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/homebrew-brewui.svg)](https://hysenlabs.com/projects/homebrew-brewui)