This script installs or updates Hugo Extended on macOS from the official GitHub release. It downloads the universal .pkg installer, checks its SHA-256 against the release metadata, and installs Hugo in /usr/local/bin. The universal package covers both Intel and Apple silicon.
As of September 21, 2026, the latest release is v0.166.0. Its macOS packages are named like hugo_extended_0.166.0_darwin-universal.pkg. The old _macOS-64bit.tar.gz pattern is gone, so the script looks up the current release every time you run it.
Before you start
You need an internet connection, an admin account, and curl, jq, and shasum in your terminal. The script checks for those 3 commands before it downloads anything. If jq is missing and you have Homebrew, run brew install jq.
Already managing Hugo with Homebrew? Stay there. brew update && brew upgrade hugo updates it, and brew install hugo handles a first install. Running both methods leaves two Hugo binaries competing in your PATH. The official macOS guide covers that route.
The script installs the Extended edition, which includes LibSass support. It doesn’t include the separate cloud deployment feature. Read the latest release notes before you upgrade an older Mac or an existing site.
Save the script
Copy this into a file named hugo_latest.sh:
#!/bin/bashset -euo pipefail
fail() { printf 'Error: %s\n' "$*" >&2 exit 1}
[[ "$(uname -s)" == "Darwin" ]] || fail "This script requires macOS."
for tool in curl jq shasum; do command -v "$tool" >/dev/null 2>&1 || fail "Required command not found: $tool"done
work_dir=$(mktemp -d)trap 'rm -rf "$work_dir"' EXIT
printf 'Finding the latest Hugo release...\n'curl --fail --silent --show-error --location \ 'https://api.github.com/repos/gohugoio/hugo/releases/latest' \ --output "$work_dir/release.json"
version=$(jq -er '.tag_name | select(test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))' \ "$work_dir/release.json")asset_name="hugo_extended_${version#v}_darwin-universal.pkg"
# Require exactly one matching asset with a SHA-256 digest.asset=$(jq -cer --arg name "$asset_name" ' [.assets[] | select(.name == $name)] | select(length == 1) | .[0] | select(.digest | strings | test("^sha256:[0-9a-f]{64}$"))' "$work_dir/release.json") || fail "No supported macOS installer with a SHA-256 digest found."
url=$(printf '%s' "$asset" | jq -er '.browser_download_url')expected_url="https://github.com/gohugoio/hugo/releases/download/$version/$asset_name"[[ "$url" == "$expected_url" ]] || fail "Unexpected installer URL."digest=$(printf '%s' "$asset" | jq -er '.digest')
printf 'Downloading Hugo Extended %s...\n' "$version"curl --fail --silent --show-error --location "$url" \ --output "$work_dir/$asset_name"
printf '%s %s\n' "${digest#sha256:}" "$asset_name" > "$work_dir/checksum.txt"(cd "$work_dir" && shasum -a 256 -c checksum.txt) \ || fail "Installer checksum verification failed."
printf 'Installing Hugo (macOS may ask for your administrator password)...\n'sudo /usr/sbin/installer -pkg "$work_dir/$asset_name" -target /
# Check the installed binary directly, even if PATH selects another Hugo.installed=$(/usr/local/bin/hugo version)[[ "$installed" == "hugo $version+extended "* ]] \ || fail "The installed Hugo did not report the expected Extended version."printf 'Installed: %s\n' "$installed"
resolved=$(command -v hugo || true)if [[ "$resolved" != "/usr/local/bin/hugo" ]]; then printf 'Your shell currently resolves hugo to: %s\n' "${resolved:-not found}" printf 'Ensure /usr/local/bin is on PATH before any other Hugo installation.\n'fiThe script stops on any download, checksum, or install error, and it deletes its temporary files on exit.
One caveat about the checksum: it catches a download that differs from GitHub’s release metadata. It’s not an independent signature check.
Run it
Open Terminal, go to the directory where you saved the file, and run:
bash hugo_latest.shOr make it executable and run it directly:
chmod +x hugo_latest.sh./hugo_latest.shRun it as your normal user. Only the install step uses sudo, so that’s the single prompt for your admin password. Installing replaces the Hugo binary this package manages in /usr/local/bin.
Verify the installation
Check the installed binary and the one your shell picks:
/usr/local/bin/hugo versioncommand -v hugohugo versionThe binary should report the version the script downloaded, with +extended. If command -v hugo points somewhere else, another installation wins in your PATH. Fix that before you assume your site builds with the new version.
Run the script again whenever you want to update. After an upgrade, build your site and read the output against the release notes.