Homebrew and asdf

Image of Author
March 10, 2022 (last updated February 7, 2023)

Homebrew, aka brew, is the "missing package manager for macOS". asdf is a version manager that lets you "manage multiple runtime versions with a single CLI tool".

Which manager do I use?

If you need to manage multiple versions of a tool, use the version manager asdf. For everything else, there's mastercard brew.

Unnecessary shims are not ideal

asdf works by prepending your path with a shims folder ~/.asdf/shims/ which contains lightweight scripts that determine (at runtime) which version of an executable to point to.

which node
# -> ~/.asdf/shims/node
asdf which node
# -> ~/.asdf/installs/nodejs/[version]/bin/node

This shims strategy makes version management easy. But, if you don't want to manage multiple versions of a tool, and simply want the most up-to-date version of a tool at any given time, use brew. Brew will symlink a tool to a common path location /usr/local/bin/, and when you upgrade a brew package/tool, it will remove the old version, and re-symlink the new version, ensuring you always get direct access to the tool (through a symlink, so maybe not theoretically direct, but definitely more direct than asdf).

which rg
# -> /usr/local/bin/rg
ls -l
# -> ... /usr/local/bin/rg -> ../Cellar/ripgrep/[version]/bin/rg

Shims impact performance

There's a script sitting in front of the call to your executable. Every time you call your executable, you wait for the script to find it. A developer prioritizing performance might find this untenable. The workaround is using direnv and asdf together. This allows you to point to the version directly. It's a great solution, but no shims to begin with might be even better (aka, use brew).

Edge Cases


Direnv is, in principle, as system tool. So, in principle, you should use brew to manage it. But, as we just saw, you might want to manage it with asdf to reap the performance benefits of using it in conjunction with asdf.

Postgresql and other database tools

(This might only apply to web devs.) Languages and frameworks often go out of their way to be database-tooling agnostic. Even when I write sql by hand I go out of my way to be database-tooling agnostic. The upside is you almost don't care about the version of your database. But, painful is the day/week/month you discover a production bug resultant from mismatching database versions in your different environments. The take away is that it might be easier in the longer run to use a version manager for your database-tooling, i.e., use asdf.

Additionally, you might be exploring the edges of your database tooling for technical/performance reasons. This is an even better reason to care about version managing your database-tooling.

The final point is a counter point: In my experience, version managing database-tooling is a bit of a hassle. As such, I will start most projects merely using brew to manage, e.g., postgresql. But, I will be quick to version manage it once I start getting nervous about environment discrepancies or start to use bespoke APIs.