Home / Alt manpages / gh-extension-upgrade(1)

  • gh-extension-upgrade(1)
  • User command
  • linux

Safely Upgrade GitHub CLI Extensions

An unattended gh extension upgrade --all can touch every extension you have in one pass, so a dry run first is not paranoia, it is the sane default. This covers previewing and upgrading one installed extension, or all of them together. 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 chase down an extension that fails to build or download.

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 need sudo when your extensions live in your user configuration directory.

1. Check the installed command

Start with read-only checks so you know which executable and version will do the upgrading:

$ 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 shape:

gh extension upgrade {<name> | --all} [flags]

The name is the short extension name, not usually the full repository name. For a 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 at all. 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 you did not expect.

3. Preview one extension

Use --dry-run with the exact name from the list to see what would happen without applying it:

$ gh extension upgrade example --dry-run

When an upgrade is available, the command reports it; when the extension is current, there may be nothing to display. A quiet result is not a failure by itself, so check the exit status 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, not a repository URL. The local manual documents --dry-run as display-only, while the plain command performs the upgrade.

4. Upgrade one extension

Once the preview looks right, 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 by listing again:

$ gh extension list

Compare the version or revision for example against what you recorded before the upgrade. If the command returns a non-zero status, stop and keep the old extension directory intact while you investigate; do not keep bolting on --force to make an unclear failure disappear.

5. Upgrade every installed extension

Once you trust the individual result, preview the complete set:

$ gh extension upgrade --all --dry-run

If the preview looks right, apply it:

$ gh extension upgrade --all

Warning

This is a batch change. One broken repository, unavailable release asset or network failure can leave the run incomplete, while output from other extensions may already have applied. Capture the terminal output on a production workstation or 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. Remove the two log files only once you have finished investigating, and keep authentication tokens or private repository URLs out of a shared report.

6. Use force only for a known stale install

The installed command also accepts --force, documented 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 install anyway, such as a known damaged checkout or a publisher-directed rebuild:

$ gh extension upgrade example --force

Warning

This is not a rollback switch and 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 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. To remove an unwanted extension, use the separate gh extension remove <name> command after saving anything you need; that is a separate, destructive action and not required to complete an ordinary upgrade.

Recovery

If the upgraded extension itself is broken, identify the exact release or commit that was installed from the list output and ask the publisher for a supported rollback procedure. gh extension upgrade documents upgrade, preview and force operations, but it does not provide a rollback flag.

Done means

  • Version and names checked: the installed GitHub CLI version and extension names were confirmed before changing state.
  • Dry run used: a preview ran for the selected extension or the complete installed set.
  • Upgrade verified: the normal upgrade completed with a checked exit status.
  • Result confirmed: gh extension list shows the resulting versions or revisions.
  • --force avoided by default: it was used only when a known local installation problem justified replacing a current copy.
  • Diagnostics preserved: any failed update left its diagnostics available without deleting the old installation by hand.