Install and Maintain GitHub CLI Extensions Safely

A GitHub CLI extension is somebody else's code running with your account's access, so gh extension is as much a trust decision as an install command. This covers inspecting what is installed, installing one from a repository, running it when its name collides with a core command, and upgrading or removing it without guessing what will change. The examples match GitHub CLI 2.87.3, installed on this machine on 23 February 2026. Allow about fifteen minutes for an existing extension and repository to be available; the commands are normally unprivileged because extensions belong to the GitHub CLI installation for your user, not to the system package manager.

1. Check the installed GitHub CLI

Start by confirming which executable and version your shell will use:

$ command -v gh
/usr/bin/gh
$ gh --version
gh version 2.87.3 (2026-02-23)

Your path and version may differ. This matters because extension behaviour is provided by the CLI, while the extension itself is a separate repository and executable. If gh is missing, stop here and install GitHub CLI through your normal distribution or vendor process. Do not use sudo merely because an extension command fails.

2. See what is already installed

List extensions before adding anything:

$ gh extension list

Each installed extension is a local gh- command. An empty result means there is nothing to upgrade or remove, not that the GitHub CLI is broken. Record the short name you intend to manage. If a name is unfamiliar, inspect its source repository before running it: an extension is executable code with the same access to your account and files as the GitHub CLI process.

Checkpoint: The name used with gh extension remove, gh extension upgrade and gh extension exec is the short name, without the gh- prefix. For a repository called owner/gh-report, the short name is report.

3. Install from a known repository

Review the repository first, then replace the placeholder with the owner and repository you have chosen:

$ gh extension install OWNER/gh-EXTENSION

The repository name must start with gh- and contain an executable of the same name. You can also pass a full repository URL when it is not hosted on GitHub:

$ gh extension install https://git.example.com/OWNER/gh-EXTENSION

For local development, the documented repository argument is a dot:

$ cd /path/to/your/gh-EXTENSION
$ gh extension install .

Installation changes your local extension set and may download or build release material. Treat a repository URL as a trust decision. Do not paste a URL from an unverified issue, comment or shell variable. To request a release tag or commit ref explicitly, use --pin:

$ gh extension install OWNER/gh-EXTENSION --pin RELEASE-TAG-OR-COMMIT

Warning: --force can force an upgrade or ignore the fact that the latest version is already installed. Use it only when you have checked why the normal install was refused. If you installed the wrong extension, the undo operation is covered in step 6.

4. Verify the command and its name

List again and run the extension using its normal short command:

$ gh extension list
$ gh EXTENSION --help

Arguments after gh EXTENSION are forwarded to the extension's executable. Keep the extension name and its arguments as separate shell words. Quote paths or values containing spaces, and inspect a command before adding credentials, file paths or destructive options.

An extension cannot override a core GitHub CLI command. If the short name conflicts with one, use the explicit executor instead:

$ gh extension exec EXTENSION --help

For example, an extension named label is run with gh extension exec label rather than gh label. The executor forwards every argument after the extension name to that extension.

5. Preview upgrades before applying them

Use the dry run when you want to see available upgrades without changing the installed extension:

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

For one extension, replace the placeholder:

$ gh extension upgrade EXTENSION --dry-run

The output is a preview, not a guarantee that a later network request will succeed. Check the name and proposed version before applying it. Then upgrade only the selected extension:

$ gh extension upgrade EXTENSION

Use --all only when upgrading every installed extension is genuinely intended. That can change several independent executables at once, making a later failure harder to isolate. --force is available for a forced upgrade, but it is not a routine repair step.

6. Remove an extension and recover from a mistake

Warning: Removal changes local state and may discard the installed extension's files. First save any extension-specific configuration or data that you need, then remove the short name:

$ gh extension remove EXTENSION

Verify the result:

$ gh extension list

There is no rollback flag in gh extension remove. Recovery means reinstalling the same repository and, if relevant, the same pinned tag or commit:

$ gh extension install OWNER/gh-EXTENSION --pin RELEASE-TAG-OR-COMMIT

If the extension came from a local development directory, return to that directory and run gh extension install . again. Reinstalling restores the executable, but it does not restore files that the extension itself may have deleted or altered.

7. Handle common failures without adding risk

If installation says that the repository is invalid, check the owner, repository spelling and required gh- prefix. A repository that lacks the matching executable cannot satisfy the extension contract. If gh extension list shows an extension but its command fails, run its help command first and check the extension's own documentation. Do not immediately reinstall with --force.

If a normal invocation appears to call a core command, use gh extension exec EXTENSION and verify the short name from the list. If an upgrade reports no change, that may simply mean the installed version is current. If an upgrade changes behaviour unexpectedly, record the previous version before further changes and reinstall a known release tag when the repository provides one.

GitHub CLI checks for extension updates once every 24 hours and may display an upgrade notice when an extension runs. This notice is separate from your explicit gh extension upgrade command. If you are writing automation, read the installed CLI's environment help before suppressing notices, and keep upgrade policy outside a job that must remain deterministic.

Done means