stout
Article

Homebrew on Apple Silicon: Performance Tips and Common Issues

Homebrew on M1/M2/M3 Macs uses /opt/homebrew instead of /usr/local. Here's what to know about ARM64 bottles, Rosetta fallbacks, and how stout handles both.

Neul Labs ·
#homebrew#apple-silicon#arm64#macos

When Apple released the M1 chip in late 2020, Homebrew had to adapt to an entirely new architecture. The transition introduced a new install prefix, ARM64-native bottles, Rosetta 2 fallback behavior, and a set of subtle issues that still trip up developers years later. Here’s a comprehensive guide to running Homebrew on Apple Silicon — and where the pain points remain.

The prefix split: /opt/homebrew vs /usr/local

On Intel Macs, Homebrew installs to /usr/local. On Apple Silicon, it installs to /opt/homebrew. This wasn’t arbitrary — /usr/local has special filesystem behavior on macOS (it’s writable without sudo on some configurations), and Apple recommended third-party software use /opt on ARM64.

This means Apple Silicon Macs may have two Homebrew installations if they previously used an Intel Mac or ran Homebrew under Rosetta:

# ARM64 native
/opt/homebrew/bin/brew

# Intel via Rosetta (if installed)
/usr/local/bin/brew

The PATH ordering determines which brew runs by default. Many issues stem from having both in PATH and inadvertently running the wrong one:

which brew
# Make sure this shows /opt/homebrew/bin/brew on Apple Silicon

ARM64 bottles vs Rosetta fallback

Homebrew distributes pre-built binaries called “bottles” for common platforms. For Apple Silicon, these are tagged with arm64_sonoma, arm64_ventura, etc. When a native ARM64 bottle exists, Homebrew downloads and installs it directly.

When no ARM64 bottle is available, Homebrew falls back to one of two strategies:

  1. Build from source for ARM64. This works for many packages but can be slow (compiling a C library takes minutes instead of seconds) and occasionally fails when the upstream source doesn’t support ARM64.

  2. Install the Intel bottle under Rosetta 2. This requires running the entire Homebrew installation under Rosetta, using the /usr/local prefix.

By 2026, the vast majority of popular formulae have ARM64 bottles. But some niche packages — especially those with assembly-optimized code or proprietary binary dependencies — may still lack native builds.

Check if a specific formula has an ARM64 bottle:

brew info --json=v2 <formula> | grep -A2 '"arm64"'

Common issues on Apple Silicon

1. “Cannot install in Homebrew on ARM processor in Intel default prefix”

This error appears when you try to run the ARM64 Homebrew with packages or configuration from an Intel installation. The fix is to ensure you’re using the correct Homebrew for your architecture:

# Check your current architecture
arch
# Should output: arm64

# Ensure /opt/homebrew is in your PATH before /usr/local
export PATH="/opt/homebrew/bin:$PATH"

If you launch Terminal.app with “Open using Rosetta” checked (sometimes done during the early M1 transition days), every command runs under Rosetta — including Homebrew. This means you’re running Intel binaries on an ARM chip with a translation layer, which adds 20-30% overhead.

Check if you’re running under Rosetta:

sysctl -n sysctl.proc_translated
# 0 = native ARM64
# 1 = running under Rosetta

If you see 1, close Terminal and uncheck “Open using Rosetta” in Get Info (right-click Terminal.app > Get Info).

3. Mixed architecture packages

Having both /usr/local (Intel) and /opt/homebrew (ARM64) installations can cause linking issues. A native ARM64 program can’t link against an Intel x86_64 library. This manifests as cryptic linker errors:

ld: warning: ignoring file /usr/local/lib/libfoo.dylib,
building for macOS-arm64 but attempting to link with file
built for macOS-x86_64

The fix is to clean up the Intel installation if you no longer need it:

# Remove the Intel Homebrew entirely
/usr/local/bin/brew list  # Check what's installed first
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"

4. Compiler and build flag issues

Some formulae that build from source may not correctly detect the ARM64 architecture and pass wrong flags to the compiler. You might see errors like:

Error: Unsupported architecture: arm64e

Or build failures related to missing NEON intrinsics vs SSE instructions. These are usually upstream issues with the formula’s build system. Workarounds include:

# Force a specific architecture
arch -arm64 brew install <formula>

# Set explicit build flags
ARCHFLAGS="-arch arm64" brew install <formula>

Performance on Apple Silicon

Despite the prefix change, the core performance characteristics of Homebrew remain the same on Apple Silicon. The Ruby interpreter is slightly faster on ARM64 due to better branch prediction and memory bandwidth, but the startup overhead is still ~450ms. Git operations on homebrew-core are marginally faster due to the improved I/O subsystem in Apple Silicon Macs, but brew update still takes 10-40 seconds.

Where Apple Silicon truly shines is in building from source. Compilation-heavy packages like gcc, llvm, or rust build 2-3x faster on M-series chips compared to Intel Macs. But this benefit is irrelevant for the 95% of packages that install via pre-built bottles.

Tips for optimizing Homebrew on Apple Silicon

Keep only the ARM64 installation. If you migrated from an Intel Mac, remove the /usr/local Homebrew installation unless you specifically need it. Two parallel installations double your update and maintenance overhead.

Verify your shell profile. Make sure /opt/homebrew/bin comes first in your PATH:

# In ~/.zshrc
eval "$(/opt/homebrew/bin/brew shellenv)"

Use arch -arm64 when in doubt. If a build fails or behaves unexpectedly:

arch -arm64 brew install <formula>

Check bottle availability before installing. For obscure packages, check if a native bottle exists to avoid long source builds:

brew fetch --bottle-tag arm64_sonoma <formula>

How stout handles Apple Silicon

stout is compiled as a universal binary with separate native builds for both ARM64 and Intel. Architecture detection is automatic — there’s no prefix confusion or Rosetta fallback behavior to manage.

stout’s SQLite index contains bottle URLs for all architectures, so it knows instantly whether an ARM64 bottle exists for any given formula. If it doesn’t, stout reports this upfront rather than silently falling back to a source build that may take minutes.

For the prefix split, stout automatically detects which prefix to use based on the running architecture. It reads the existing Cellar from whichever prefix is active, maintaining full compatibility with packages installed by Homebrew.

The performance advantages of stout are consistent across Intel and Apple Silicon: ~5ms startup (vs ~450ms), 1-3 second index updates (vs 10-40 seconds), and parallel downloads regardless of platform. The difference is that on Apple Silicon’s fast I/O subsystem, the absolute numbers for stout are even lower — index updates often complete in under a second.

If you’re running Homebrew on Apple Silicon, most of the architecture-specific issues are solvable with the right PATH configuration and prefix management. But the core performance issues — Ruby startup, git-based updates, sequential downloads — are architectural, not platform-specific, and they follow Homebrew to every platform it runs on.

Need Rust performance engineering or AI agent expertise?

Neul Labs — the team behind stout — consults on Rust development, performance optimization, CLI tool design, and AI agent infrastructure. We build fast, reliable systems that ship.