On an Apple Silicon Mac, Homebrew installs under /opt/homebrew instead of the /usr/local prefix it uses on Intel Macs. Why does that split exist, and what has to be configured before the shell finds brew-installed commands?
answer
- bottles are built for one known prefix
- two architectures can coexist on one Mac
- one prefix is already in /etc/paths, the other is not
- brew shellenv exists for a reason
- never hardcode the prefix in a script
basics
~20 sHomebrew uses a separate /opt/homebrew prefix on Apple Silicon so an arm64 installation can coexist with an Intel one under /usr/local and so bottles are built for a known default prefix. That directory is not on the default PATH, so brew shellenv must add it.
solid answer
~50 sPrebuilt bottles are built against a fixed default prefix, so Homebrew needs one canonical location per architecture. `/usr/local` was already the Intel prefix, and after Apple Silicon arrived a machine can legitimately run both an arm64 Homebrew and an x86_64 one under Rosetta — so the native install got a fresh prefix, `/opt/homebrew`. The practical consequence is PATH: macOS ships `/usr/local/bin` in the default PATH but not `/opt/homebrew/bin`, so on Apple Silicon nothing works until you run `eval "$(/opt/homebrew/bin/brew shellenv)"` from your login profile, which sets `HOMEBREW_PREFIX` and prepends the prefix's `bin` and `sbin`. Two other things follow. Machines migrated from an Intel Mac often carry an x86_64 Homebrew in `/usr/local` that still works under Rosetta and quietly installs Intel binaries. And scripts should never hardcode a prefix — ask `brew --prefix` so the same script works on both.
code
bash · 8 lines# Native Apple Silicon Homebrew is not on the default PATH.
eval "$(/opt/homebrew/bin/brew shellenv)"
# Now resolve paths from brew rather than hardcoding a prefix.
echo "$HOMEBREW_PREFIX"
CFLAGS="-I$(brew --prefix openssl@3)/include"
LDFLAGS="-L$(brew --prefix openssl@3)/lib"
echo "$CFLAGS $LDFLAGS"go deeper
Know that Homebrew lives in /opt/homebrew on Apple Silicon Macs and /usr/local on Intel ones, and that on Apple Silicon you must run brew shellenv from your login profile before commands are found.
Explain why: bottles target a fixed default prefix, and separate prefixes let a native arm64 install and a Rosetta x86_64 install coexist. Describe how PATH order decides which of two identically named binaries runs.
Diagnose the mixed-architecture machine — a Homebrew inherited from an Intel Mac quietly serving x86_64 binaries under Rosetta — and enforce prefix-agnostic scripts by resolving paths through brew --prefix.
Own the fleet consequence: a mixed Intel and Apple Silicon estate means no script, CI job or internal tool may assume a prefix, and you decide whether a Rosetta escape hatch is a supported configuration or something the team must migrate off.
## Why a prefix is a fixed thing at all Homebrew rarely compiles on your machine. It downloads a **bottle** — a binary tarball built by Homebrew's CI. Compiled binaries and libraries contain absolute paths (install names, rpaths, embedded data directories), and while Homebrew does relocate bottles, that relocation is cheapest and most reliable when the target is the prefix the bottle was built for. Installing into a non-default prefix is supported but pushes many formulae into building from source and is explicitly unsupported territory. So each platform gets one blessed default prefix. - Intel macOS: `/usr/local` - Apple Silicon macOS: `/opt/homebrew` Homebrew 3.0 (2021) is where native Apple Silicon support and `/opt/homebrew` arrived. ## Why not reuse /usr/local on Apple Silicon Two reasons, and interviewers want both. **Coexistence.** An Apple Silicon Mac can run x86_64 binaries through Rosetta 2. Early on, plenty of formulae had no arm64 bottle, and some still have Intel-only dependencies. Homebrew's supported answer is to run a *second*, Intel Homebrew under `/usr/local`, driven through Rosetta: ```bash arch -x86_64 /usr/local/bin/brew install some-intel-only-tool ``` If both installs shared a prefix, the Cellar would contain a mix of arm64 and x86_64 kegs with the same names and the symlinks would fight. Separate prefixes make the two installations independent. **Legacy.** `/usr/local` on an Intel Mac had years of accumulated non-Homebrew content — hand-built software, vendor installers, stray package payloads. Starting the new architecture in a clean directory Homebrew owns outright avoided inheriting that mess. ## The PATH consequence, which is the real question macOS builds the default PATH from `/etc/paths` and the fragment files in `/etc/paths.d`, assembled by Apple's `/usr/libexec/path_helper`, which the system's login profile runs. `/etc/paths` already lists `/usr/local/bin` ahead of `/usr/bin` — which is why Homebrew on an Intel Mac appears to "just work" with no configuration. `/opt/homebrew/bin` is in none of that. On Apple Silicon you must add it yourself, and the supported way is: ```bash eval "$(/opt/homebrew/bin/brew shellenv)" ``` `brew shellenv` emits exports for `HOMEBREW_PREFIX`, `HOMEBREW_CELLAR` and `HOMEBREW_REPOSITORY`, and prepends the prefix's `bin` and `sbin` to `PATH` plus the corresponding `MANPATH` and `INFOPATH` entries. It belongs in the login profile, and it must run *after* `path_helper` has built its PATH — `path_helper` puts the entries from `/etc/paths` at the front, so a PATH you set earlier can be reordered out from under you and Homebrew's binaries end up losing to Apple's. That ordering is the whole game. Both `/usr/bin/python3` and a Homebrew Python can exist; which one runs is decided purely by which prefix comes first. `which -a <cmd>` shows every match in order and is the fastest way to settle an argument about it. ## The migration trap Migration Assistant happily copies an Intel Mac's `/usr/local` onto a new Apple Silicon machine. Everything still runs — through Rosetta — so nothing looks broken. The symptoms are subtler: builds are slow, native extensions compile for the wrong architecture, and a mixed environment appears where some tools are arm64 and some are x86_64. The diagnosis is quick: ```bash uname -m # arm64 on Apple Silicon which -a brew # /opt/homebrew/bin/brew? /usr/local/bin/brew? both? file $(which node) # Mach-O arm64 vs x86_64 ``` The fix is to install the native Homebrew into `/opt/homebrew`, reinstall the formulae there, and either remove the `/usr/local` install or keep it deliberately as the Rosetta escape hatch — never by accident. ## What this means for scripts and CI Hardcoding a prefix is the defect this question is really hunting for. A Makefile with `-I/usr/local/include`, a CI script sourcing `/usr/local/bin/brew`, or a shebang pointing at `/usr/local/bin/python3` breaks on every Apple Silicon machine and on every mixed fleet. Ask instead: ```bash brew --prefix # the install prefix brew --prefix openssl@3 # a specific formula's keg path ``` and use `$HOMEBREW_PREFIX` when `brew shellenv` has already run. The same discipline handles keg-only formulae, whose headers and libraries are never linked into the prefix at all and must be found through `brew --prefix <formula>`.
- How would you tell whether a command on an Apple Silicon Mac is running natively or under Rosetta?Check the binary, not the machine: `file $(which <cmd>)` reports the Mach-O architecture, and `lipo -info` lists the slices of a universal binary. `uname -m` only tells you the architecture of the *current* process — inside a shell started with `arch -x86_64` it prints x86_64 on an Apple Silicon Mac, which is exactly the confusion to watch for.
- Why is hardcoding /usr/local/include in a Makefile a defect on a modern Mac?It encodes the Intel prefix. On Apple Silicon the headers live under /opt/homebrew, and for keg-only formulae they are not in the prefix's include directory at all. `brew --prefix` and `brew --prefix <formula>` resolve the right path on both architectures and for keg-only kegs, so the same build works everywhere.
- Is it ever legitimate to have both /opt/homebrew and /usr/local Homebrew installations on one machine?Yes, deliberately: the /usr/local install run through `arch -x86_64 /usr/local/bin/brew` is the supported way to get formulae that still have no arm64 bottle. The rule is that it must be intentional and PATH-ordered so the native prefix wins by default; an accidental duplicate inherited from Migration Assistant is the failure mode.
saying these in an interview costs you the question
- Assuming /opt/homebrew is on the default PATH like /usr/local
- Thinking the prefix change was cosmetic rather than architectural
- Hardcoding /usr/local paths in build scripts and shebangs
- Believing an Intel Homebrew cannot run on Apple Silicon at all
- Trusting uname -m to prove a binary is native