## Install (the short version)
“`bash
# Run once: prereqs on Debian / Ubuntu
sudo apt install build-essential procps curl file git
# Install Homebrew to /home/linuxbrew/.linuxbrew
/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”
# Add to PATH (next steps in the installer output)
test -d /home/linuxbrew/.linuxbrew
&& eval “$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)”
# Persist the PATH in your shell rc
echo ‘eval “$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)”‘ >> ~/.bashrc
“`
On Fedora / RHEL: `sudo dnf group install “Development Tools” && sudo dnf install procps-ng curl file`. Same logic. On Arch: `sudo pacman -S base-devel procps-ng curl file git`.
**Install path is fixed at `/home/linuxbrew/.linuxbrew`.** The Homebrew installer chose this so that:
– Pre-compiled bottles (binary packages) work without rebuilding against system libraries.
– Homebrew never writes to system-owned directories (`/usr`, `/opt`, `/usr/local`).
– You don’t need root after install.
The trade-off is that you can’t install it to `/opt/homebrew` (the Apple Silicon Mac path) or `/usr/local` (Intel Mac path). On Linux it’s `/home/linuxbrew/.linuxbrew`, single-user.
## The four cases where Homebrew on Linux earns the install
### Case 1 — You use the same dev tool on Mac and Linux
The killer use case for Homebrew on Linux is people who maintain a Mac workstation and a Linux server / WSL box and want the same commands to install the same versions of the same tools. With `brew`, both boxes can run:
“`bash
brew install postgresql@16 redis ffmpeg jq yq fd ripgrep
“`
…with the same semantics on both platforms. On Mac you’d also write a `Brewfile`:
“`ruby
# Brewfile
tap “homebrew/bundle”
tap “homebrew/services”
brew “postgresql@16”
brew “redis”, restart_service: true
brew “ffmpeg”
brew “jq”
cask “iterm2”
mas “Xcode”, id: 497799835
“`
…and run `brew bundle –global` on the Linux box too. **The `Brewfile` is portable across macOS and Linux** as long as every formula you list has a Linux bottle, which most popular ones do.
This is the canonical use case. If you’re not juggling Mac and Linux, you’re not the audience.
### Case 2 — You want a newer version of a tool than your distro ships
Debian 13 ships PostgreSQL 15. Ubuntu 26.04 ships it too. If you want PostgreSQL 17, you have three options: (a) add PostgreSQL’s official APT repo (`apt.postgresql.org`); (b) build from source; (c) `brew install postgresql@17`.
“`bash
brew install postgresql@17
brew services start postgresql@17
“`
And Homebrew runs it as a systemd-style service under the current user. The Linux distro package manager has no idea it exists. Symlinks land in `~/.linuxbrew/bin/`, which is the first in your PATH for that shell session.
Other version-cases where Homebrew wins:
– **Node.js**: `brew install node@22` → node 22 LTS, no nvm needed
– **Python**: `brew install python@3.13` → recent Python with `pip`, without needing `pyenv`
– **OpenJDK**: `brew install openjdk@21` → 21 LTS
– **ffmpeg**: Homebrew’s ffmpeg is built with more codecs enabled than Debian’s stripped-down package
– **PostgreSQL**: as above
### Case 3 — You want a self-contained, reproducible dev environment per project
The `Brewfile` + `brew bundle` flow is the cleanest cross-platform dotfiles replacement. With a `Brewfile` committed to your repo, `brew bundle` reads it and ensures every mac and every Linux machine you `git clone` onto can be brought to the same tool state in one command:
“`bash
git clone https://github.com/myorg/devtools.git ~/devtools
cd ~/devtools && brew bundle
“`
For a single per-project Brewfile (in a project root), the convention is to run `brew bundle –install –no-upgrade` against the project’s `Brewfile.lock` for reproducible installs.
This is also how CI builds sometimes work — many Linux CI images ship a Brew-prefixed toolchain to keep image size down and reproducibility high.
### Case 4 — You run services via `brew services` on Linux (joke-but-true)
Yes, `brew services` runs on Linux. It launches services under systemd’s `–user` mode if available, falling back to launchd or direct process. PostgreSQL, Redis, MySQL — all available with `brew services start postgresql@17`. If you’re running a dev box with multiple Postgres versions for testing schema upgrades, you can run postgresql@15 from apt AND postgresql@17 from brew simultaneously, on different ports. This is genuinely cleaner than juggling multiple apt repo sources.
## When Homebrew on Linux is the wrong call
### Don’t use Homebrew on a production server
Homebrew’s prefix is `/home/linuxbrew/.linuxbrew`. That means:
– It’s not in `/usr/bin`, `apt`’s awareness, or your distro’s update path
– It doesn’t get security patches unless you `brew upgrade` manually
– Nothing on the system knows about it except `brew` itself
If you’re running a production Debian server, use **Debian’s packages** or the project’s **official APT repo**. The OS update flow will catch all security patches. A Homebrew-prefixed service isn’t getting the right attention from the OS package manager.
### Don’t use Homebrew for system-level daemons
If you’re deploying nginx / postgres / redis for “the whole machine”, apt has a better story because it integrates with `systemctl` properly and the OS package state is auditable. Homebrew’s user-level services are great for dev workflow but not for production.
### Don’t use Homebrew as your only tool
apt is your base layer. You always have apt. Adding Homebrew as a second tool alongside apt means **two package managers, two update cadences, two mental models**. If you go down this path, be honest with yourself: you’re now maintaining the toolchain twice, and apt is the one that’s getting auto-updates.
A reasonable pattern: use **apt for the OS-tier** (kernel-adjacent libraries, the desktop, networking daemons, libreoffice) and **brew for the dev tier** (postgresql@17, node@22, recent ffmpeg, jq, fd, ripgrep, language-specific toolchains). Don’t try to manage everything from brew or everything from apt.
### Don’t use Homebrew if your distro is already rolling-release
If you’re on Arch, openSUSE Tumbleweed, or NixOS, your distro’s packages are already current enough that Homebrew doesn’t unlock anything. The `brew install node@22` example might give you a slightly different version than `pacman -S nodejs-lts`, but the difference doesn’t justify installing a second package manager on a system that’s already current. Stick with the distro packages, add a PPA if you really need a specific newer package.
### Don’t use Homebrew on WSL 1
WSL 1 has known compatibility issues with Homebrew bottles. WSL 2 is fine. WSL 1 is below Tier 3 support per the official docs. If you’re on WSL 1, upgrade to WSL 2 first (`wsl –set-version
## Common surprises for Mac users on Linux Brew
1. **The install path is `/home/linuxbrew/.linuxbrew`, not `/opt/homebrew`.** Commands you see on the internet that say `$(/opt/homebrew/bin/brew shellenv)` will fail. Replace with the Linux path.
2. **No Cask room for `.app` bundles.** Casks on Mac put `.app` files in `/Applications`. On Linux there’s no `/Applications`, so casks that install .app bundles are essentially non-functional. Some casks on Linux install different formats (`AppImage`, `deb`) — see `info.brew.sh` for each cask to know which.
3. **`brew doctor` complains less on Linux.** The Homebrew diagnostic that says “this is set up well” is more permissive on Linux, because the Linux filesystem has fewer quirks.
4. **Compilation is more likely to fail.** Linux packages almost always compile from source if the bottle isn’t available for your exact OS version. The bottle registry has good coverage for Ubuntu LTS and current Debian stable; on Fedora or Arch you may compile more often.
5. **Update is slow.** `brew update && brew upgrade` can take minutes on Linux. The bottleneck is the formula index fetch and the bottles’ linkage resolution. macOS is faster because of system-shared libraries.
## Common surprises for Linux users coming to Homebrew
1. **Brew is *not* a system-wide tool.** Don’t `sudo brew install` anything after install. If you used `sudo` with `curl | bash` for the install, that’s the only sudo interaction.
2. **The `keg_only` concept is different from `apt`.** Some formulae are `keg_only`, meaning their binaries don’t symlink into `~/.linuxbrew/bin/` by default. They live in `~/.linuxbrew/Cellar/
3. **Formulae can break things.** `brew install openssl@3` will symlink its libssl over your system libssl if you let Homebrew “link” aggressively. Don’t `brew link –force openssl`. Use `–ignore-dependencies` or `keg_only` modes intentionally.
4. **No apt-cache equivalent.** There’s `brew info`, but it’s slow and online-only. There’s `brew search`, which is also online.
5. **Upgrading is manual.** `brew outdated && brew upgrade` is the closest analog to apt’s auto-update. There’s no apt-mark equivalent.
## The honest side-by-side with apt
| Job | apt | Homebrew on Linux |
|—|—|—|
| Install a CLI tool | `apt install ripgrep` | `brew install ripgrep` |
| Install recent version | Depends on Debian backports / PPA / upstream APT repo | `brew install postgresql@17` (no extra sources needed) |
| Reproducible per-project | Not great — you can pin with `apt-mark hold` but it’s coarse | `Brewfile` + `brew bundle –no-upgrade` |
| Multi-OS dotfiles | No native solution | Same `Brewfile` for Mac and Linux |
| Tooling per process / per shell | Not really | `brew shellenv`, keg-only overrides |
| System-level services | First-class apt + systemd | `brew services start`, less integrated |
| Security updates | Auto (apt unattended-upgrades) | Manual `brew upgrade` (Homebrew has a `brew autoupdate` command you can schedule) |
| Performance | Native | Bottles are precompiled; source builds are slow but cached |
| Source of truth | Distro-packaged upstream | Brew team’s own fork of formulae |
| License | Whatever Debian licenses | DFSG-compatible open source for `homebrew/core` |
## A realistic setup pattern for 2026
If I were setting up a dev workstation on Debian 13 today:
“`bash
# Use apt for the OS tier
sudo apt install build-essential git curl wget vim neovim tmux
zsh ripgrep fd-find bat jq fzf htop
network-manager-openvpn gnome-shell-pomodoro
# Use brew for the dev tier
/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”
eval “$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)”
brew install python@3.13 node@22 postgresql@17 redis ffmpeg
# Track in a single Brewfile in your dotfiles repo
cat > ~/dotfiles/Brewfile <
Comments