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.
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.
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.
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.
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.
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.
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.
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.
gh --version identifies the CLI release you intended to use.gh extension list shows only repositories you recognise.gh extension exec when a core name conflicts.