Installing Old Homebrew Formula Versions

Christian Emmer
Christian Emmer
Aug 13, 2025 · 3 min read
Installing Old Homebrew Formula Versions

Homebrew makes it very difficult to install older versions of a formula.

And no, versioned formulae are not a real solution. Thankfully, we can cobble together some incantations to get what we want.

The solution comes from Carlo Cabrera on GitHub . It involves:

  1. Making a local tap ("local" because we won't be publishing this to a remote Git repository)
  2. Copying a specific version of a formula to our local tap
  3. Installing the local copy of the formula

Installation

For our example formula, I'm going to use Zstd v1.5.5. This came from a real world need of mine while developing Node-API modules for Igir .

First, we need to check out the entire Git history of homebrew/core so that brew can scan its history for the desired version of the formula:

brew tap --force homebrew/core

We only need to tap once. Subsequent runs should use brew update to update the tap.

Then, we need to make our local tap. We only need to do this once ever:

brew tap-new homebrew/local

Then, we'll "extract" (copy) a specific version of a formula into our local tap. Again, we'll only need to do this once ever:

brew extract --version=1.5.5 zstd homebrew/local

Then, we'll install the formula, which may cause a build process:

brew install homebrew/local/zstd@1.5.5

Note: you can use the command brew edit homebrew/local/zstd@1.5.5 to edit the formula file in case of build failures. In the case of Zstd v1.5.5, I needed to add -DCMAKE_POLICY_VERSION_MINIMUM=3.5 to the cmake command to get the build to succeed.

Typically brew install will create all appropriate symlinks, but if you already have the formula installed then you'll need to follow the printed instructions to overwrite the symlinks:

brew link --overwrite zstd@1.5.5

Uninstallation

If you later want to swap back to the latest version, run the commands:

brew unlink zstd
brew link --overwrite zstd

To delete the formula that you copied to local disk, run:

brew uninstall zstd@1.5.5

To delete the local tap and all copied formulae, run:

brew untap homebrew/local

And to remove your local copy of homebrew/core (and stop it from updating on every brew update), run:

brew untap homebrew/core

As a dotfile function

We can tie everything together into one clean function that you can put in your dotfiles:

# Install a specific version of a Homebrew formula
# @param {string} $1 Formula name
# @param {string} $2 Formula version
vintage() {
    # Ensure homebrew/core is tapped and up to date
    brew tap | grep --quiet --line-regexp homebrew/core \
        && brew update \
        || brew tap --force homebrew/core

    # Ensure homebrew/local is created
    brew tap | grep --quiet --line-regexp homebrew/local \
        || brew tap homebrew/local

    # Extract the formula
    brew extract --force "--version=${2:?}" "${1:?}" homebrew/local

    # If the formula is already installed, re-link it
    if brew list -1 | grep --quiet --line-regexp "${1:?}@${2:?}"; then
        brew unlink "${1:?}@${2:?}"
        brew link --overwrite "${1:?}@${2:?}"
        return 0
    fi

    # Install the formula and ensure it's linked
    brew install "homebrew/local/${1:?}@${2:?}" \
        || brew link --overwrite "${1:?}@${2:?}"
}

Caveats

The main caveat is if you're installing an older version of a formula, it may need old versions of its dependencies. Each situation is going to be unique, but some situations may be resolved by making changes to the formula file and then running brew install again:

brew edit homebrew/local/zstd@1.5.5