
Homebrew makes it very difficult to install older versions of a cask.
Homebrew casks are a way to install macOS GUI applications (i.e. in the /Applications
directory). Unlike Homebrew formulae, casks aren't typically symlinked.
Installing old versions of casks is more complicated than installing old versions of formulae, as there is no brew extract --cask
command (as of writing).

Installing Old Homebrew Formula Versions
Aug 13, 2025 · 4 min read
Homebrew makes it very difficult to install older versions of a formula.
Installation
For our example cask, I'm going to use Amazon Corretto v24. This came from a real world need of mine to install non-LTS JDK versions at work. The only versioned casks for Corretto is for LTS JDK versions (corretto@17
, corretto@21
, corretto@25
, etc.), so there is no corretto@24
. Instead, we have to install an old version of corretto
when it was v24.
First, we need to check out the entire Git history of homebrew/cask so that git
can scan its file history for the desired version of the application:
brew tap --force homebrew/cask
We only need to tap once. Subsequent runs should use brew update
to update the tap.
Then, we need to make our local tap. Again, we only need to do this once ever:
brew tap-new homebrew/local
Then, we'll need to figure out the path of the cask's Ruby file. As of writing, this would be Casks/<letter>/<cask>.rb
, but a more resilient approach would be:
$ cd "$(brew --repository homebrew/cask)"
$ git ls-files 'Casks/*' | grep -E "/corretto\.rb$"
Casks/c/corretto.rb
Then, we'll need to figure out the commit hash that updated the cask file to our desired application version. Here we'll print all Corretto v24 versions:
$ cd "$(brew --repository homebrew/cask)"
$ git rev-list --all Casks/c/corretto.rb \
| xargs -n1 -I% git --no-pager grep --fixed-strings "version \"24." % -- Casks/c/corretto.rb
51d5d6c524854fe11dfa82c5b7439e6a502c47cf:Casks/c/corretto.rb: version "24.0.2.12.1"
a780d8ca78c3072c8c43ae6ed9108041c722fff0:Casks/c/corretto.rb: version "24.0.1.9.1"
fe80d7e571d831942cf19f923be20db84bcd8738:Casks/c/corretto.rb: version "24.0.0.36.2"
Then, we'll write the contents of the desired file version to our local homebrew/local
tap. I'm choosing to use a naming scheme similar to versioned casks , which requires changing the cask name within the file. We'll only need to do this file write once ever:
cd "$(brew --repository homebrew/cask)"
git show "51d5d6c524854fe11dfa82c5b7439e6a502c47cf:Casks/c/corretto.rb" \
| sed "s/cask \"corretto\"/cask \"corretto@24.0.2.12.1\"/" \
> "$(brew --repository homebrew/local)/Casks/corretto@24.0.2.12.1.rb"
Then, we'll install the cask:
brew install --cask homebrew/local/corretto@24.0.2.12.1
Uninstallation
To uninstall all applications provided by the cask, run:
brew uninstall corretto@24.0.2.12.1
To delete the local tap and all cask files, run:
brew untap homebrew/local
And to remove your local copy of homebrew/cask (and stop it from updating on every brew update
), run:
brew untap homebrew/cask
As a dotfile function
Combining this together with the easier method to install old formula versions, we can write one clean function that you can put in your dotfiles:

Installing Old Homebrew Formula Versions
Aug 13, 2025 · 4 min read
Homebrew makes it very difficult to install older versions of a formula.
# Install a specific version of a Homebrew formula
# @param {string} $1 Formula name
# @param {string} $2 Formula version (exact)
vintage() {
# Figure out the relevant tap
local brew_tap
local is_cask=false
if brew search --cask "/^${1:?}$/" &> /dev/null; then
brew_tap="homebrew/cask"
is_cask=true
else
brew_tap="homebrew/core"
fi
# Ensure the appropriate tap is tapped and up to date
if brew tap | grep -xq "${brew_tap}"; then
brew update
else
brew tap --force "${brew_tap}"
fi
# Ensure homebrew/local is created
brew tap | grep -xq homebrew/local \
|| brew tap homebrew/local
if [ "${is_cask}" = false ]; then
# If the formula is already installed, re-link it
if brew list -1 | grep -xq "${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:?}"
else (
# Sub shell to make `cd` safe
cd "$(brew --repository "${brew_tap}")" || return 1
# Emulate `brew extract` for casks
local cask_path
cask_path=$(git ls-files 'Casks/*' | grep -E "/${1:?}\.rb$")
local version_match
version_match=$(git rev-list --all "${cask_path}" \
| xargs -n1 -I% git --no-pager grep --fixed-strings "version \"${2:?}\"" % -- "${cask_path}" \
2> /dev/null | head -1)
local commit_hash="${version_match%%:*}"
local local_cask_dir
local_cask_dir="$(brew --repository homebrew/local)/Casks"
if [ ! -d "${local_cask_dir}" ]; then
mkdir -p "${local_cask_dir}"
fi
local local_cask_file="${local_cask_dir}/${1:?}@${2:?}.rb"
git show "${commit_hash}:${cask_path}" \
| sed "s/cask \"${1:?}\"/cask \"${1:?}@${2:?}\"/" \
> "${local_cask_file}"
# Install the formula
brew install --cask "homebrew/local/${1:?}@${2:?}"
) fi
}