How to migrate to native Homebrew on an M1 Mac

Let the great Homebrew migration begin. Yes, Homebrew now has native support for Apple’s ARM64-based M1 chip. The latest version, 3.0.0, released 5 February, will run nicely on your Apple Silicon Mac. There’s a catch, of course. Well, several catches: first, not all of the tools you can install using Homebrew are M1 native yet and, second, Homebrew doesn’t offer explicit migration instructions, that I could find at least.

Apple Silicon Mac, now with native Homebrew support

So I leapt in and hoped for the best. I’ve been using a mix of native Terminal (for tool usage) and Terminal under Rosetta 2 (for tool installation and upgrades), so anything that saves me from maintaining two Termini or temporarily switching the Open using Rosetta option in the utility’s Get Info panel (and usually forgetting to switch it back afterwards) is a bonus. Here’s what I did.

First, re-run the Homebrew installer. On an M1 Mac it will create a new installation under /opt/homebrew (on Intel it’s under /usr/local/bin).

If you’ve been using Homebrew under emulation, you now have two side-by-side installs, so from this point on it’s a matter of working tool by tool, installing an ARM64 versions then removing the x86-64 version. Tools that lack ARM64 versions can stay in the emulated world — just move on to the next one.

Edit your .bash_profile or .zshrc file to update any PATH additions or aliases to the new Homebrew installation. For example, alias nano=/opt/homebrew/bin/nano instead of alias nano=/usr/local/bin and export PATH="/opt/homebrew/bin:$PATH" in place of export PATH="/usr/local/bin:$PATH". But do read on for a solution that works with multiple Macs of different CPU architectures.

I didn’t do this at this point, but were I to do all this again, I would add a further alias: alias oldbrew=/usr/local/bin/brew just to make accessing the old install a little more convenient.

I had side-by-side terminal tabs, one for brew … and the other for /usr/local/bin/brew … as I worked through my installed tools to check they install natively in the first tab and, if so, uninstalling the non-native version from the second tab.

I found that the majority of my previously installed tools have ARM64 versions, including some, like the Go language, which did not when I last checked, a few weeks ago. I can now build my websites with Hugo running on Go natively. Python 3.9 is M1 native, so that saves a lot of bother; I was able to rip out the non-native version entirely. Your mileage will vary according to which tools you use.

For example, I use shellcheck for linting Bash scripts, but it’s not yet native and, as the Homebrew folk warn might be the case, can’t be built from source, at least not using Homebrew. Fortunately, I don’t use shellcheck regularly, so I can afford to wait for native support among all of its many dependencies. It still runs, of course, under Rosetta. I just need to try to re-install it using the native Homebrew every so often, or keep tabs on the Homebrew GitHub repo.

Once you’ve done, it’s worth running brew cleanup to clear out any cruft from each install and then manually deleting any remaining orphaned files and links from /usr/local — look in the various sub-directories, including Caskroom, Cellar, Frameworks, Homebrew, and lib. If all of your Homebrew-installed tools are now native, you may not want to keep the old Homebrew install, and so the first four of these can probably be deleted.

Take care with the contents of /usr/local/bin — you may have tools there that were not installed by Homebrew, or were installed by Homebrew but with fixed install locations. For instance, my command line tools imageprep, pdfmaker and utitool continue to install into /usr/local/bin even when installed by M1-native Homebrew and even though they contain native ARM64 code.

Multiple Homebrews on multiple Macs

If, like me, you have multiple Macs with different CPU architectures, you can add something like this to your .bash_profile or .zshrc file:

# Handle Mac platforms
CPU=$(uname -p)
if [[ "$CPU" == "arm" ]]; then
    export PATH="/opt/homebrew/bin:$PATH"
    export EDITOR=/opt/homebrew/bin/nano
    alias nano=/opt/homebrew/bin/nano
    alias oldbrew=/usr/local/bin/brew
    export PATH="/usr/local/bin:$PATH"
    export EDITOR=/usr/local/bin/nano
    alias nano=/usr/local/bin/nano

See Also