Safely Upgrade GitHub CLI Extensions
You will preview and then upgrade one installed GitHub CLI extension, or all installed extensions in one operation. The examples use GitHub CLI 2.87.3, installed on this machine on 23 February 2026. Allow about ten minutes for a normal update, plus time to investigate an extension that fails to build or download.
The route
Jump straight to the step you need, or tick off Done means at the end.
You need gh installed and an authenticated account if the extension's repository is private. Extension upgrades change programs in your local GitHub CLI installation. They do not update GitHub CLI itself, and they do not require sudo when your extensions are in your user configuration directory.
1. Check the installed command
Start with read-only checks so you know which executable and version will perform the upgrade:
$ command -v gh
/usr/bin/gh
$ gh --version
gh version 2.87.3 (2026-02-23)
https://github.com/cli/cli/releases/tag/v2.87.3
$ gh extension upgrade --help
Upgrade installed extensions
The installed manual gives this command shape:
gh extension upgrade {<name> | --all} [flags]
The name is the short extension name, not normally the full repository name. For an extension repository called owner/gh-example, the command name is usually example.
2. Record what is installed
List the local extensions before changing anything:
$ gh extension list
NAME REPO VERSION ACTIVE
The output is host-specific. On a machine with no extensions, the command can print only its heading or no rows. If the list is empty, there is nothing for gh extension upgrade --all to update. If an extension is marked active, treat it as a program you trust and use regularly, not as harmless package data.
GitHub's documentation states that extensions are not verified, signed or endorsed by GitHub. An upgrade runs code from the extension publisher, so review the repository and release provenance before accepting an update that you did not expect.
3. Preview one extension
Use --dry-run with the exact name from the list. This displays available upgrades without applying them:
$ gh extension upgrade example --dry-run
When an upgrade is available, the command reports it. When the extension is current, there may be no upgrade to display. A quiet result is not a failure by itself, so check the exit status when using the command in a script:
$ gh extension upgrade example --dry-run
$ printf 'dry-run exit status: %s\n' "$?"
dry-run exit status: 0
Replace example with a real installed name. Do not use a repository URL here. The local manual documents --dry-run as display-only, while the plain command performs the upgrade.
4. Upgrade one extension
After checking the preview, run the same command without --dry-run:
$ gh extension upgrade example
Upgraded extension example
The exact success message depends on the extension and its installation type. Verify the result by listing extensions again:
$ gh extension list
Compare the version or revision shown for example with the value recorded before the upgrade. If the command returns a non-zero status, stop and keep the old extension directory intact while you investigate the error. Do not repeatedly add --force to make an unclear failure disappear.
5. Upgrade every installed extension
Once you are comfortable with the individual result, preview the complete set:
$ gh extension upgrade --all --dry-run
If the preview is expected, apply it:
$ gh extension upgrade --all
This is a batch change. One broken repository, unavailable release asset or network failure can make the run incomplete, and output from other extensions may already have been applied. Capture the terminal output if this is a production workstation or a shared administrative host:
$ gh extension upgrade --all 2>gh-extension-upgrade.err | tee gh-extension-upgrade.log
$ status=${PIPESTATUS[0]}
$ printf 'upgrade exit status: %s\n' "$status"
$ test "$status" -eq 0
The PIPESTATUS check matters because a successful tee can otherwise hide a failed gh command in Bash. The two log files are local working files. Remove them only after you have finished investigating, and do not include authentication tokens or private repository URLs in a shared report.
6. Use force only for a known stale install
The installed command also accepts --force. Its documented purpose is to force an extension upgrade. Use it only when the normal check says the extension is current but you have a specific reason to replace the local installation, such as a known damaged checkout or a publisher-directed rebuild:
$ gh extension upgrade example --force
This is not a rollback switch and it is not a security check. It can replace a working local copy, so preserve any local modifications or record the installed revision first. If you installed an extension from a local development repository, inspect its current state before forcing an upgrade. A local change may be overwritten or disconnected from the managed installation.
7. Recover from an unsuccessful update
First confirm what remains installed:
$ gh extension list
$ gh extension upgrade example --dry-run
For a failed download or build, check network access, repository permissions and the extension's own release instructions. A failed upgrade does not justify deleting the extension directory by hand. If you need to remove an unwanted extension, use the separate gh extension remove <name> command after saving any data or local work you need. Removing an extension is a separate, destructive action and is not required to complete an ordinary upgrade.
If the upgraded extension itself is broken, identify the exact release or commit that was installed from the list output and consult the extension publisher for a supported rollback procedure. The gh extension upgrade command documents upgrade, preview and force operations, but it does not provide a rollback flag.
Done means
- The installed GitHub CLI version and extension names were checked before changing state.
- A dry run was used for the selected extension or the complete installed set.
- The normal upgrade completed with a checked exit status.
gh extension listshows the resulting extension versions or revisions.--forcewas avoided unless a known local installation problem justified replacing a current copy.- Any failed update left its diagnostics available without deleting the old installation by hand.