An extension called label and the built-in gh label command cannot both answer to plain gh label, so gh extension exec forces the extension to run. Allow about ten minutes. You need GitHub CLI and at least one installed extension; the examples use the gh 2.87.3 installed on this machine.
This command only runs an extension: it does not install, upgrade or remove one. Those are separate operations, so nothing here needs elevated privileges or changes your GitHub CLI installation.
Confirm which executable you are using and record its version. Both are ordinary, read-only checks:
$ command -v gh
/usr/bin/gh
$ gh --version
gh version 2.87.3 (2026-02-23)
Your version may differ; the syntax here is whatever the installed gh-extension-exec(1) manual on your machine documents.
Checkpoint: ask for the subcommand's help without trying to execute an extension:
$ gh help extension exec
Execute an extension using the short name.
USAGE
gh extension exec <name> [args] [flags]
The help text can carry extra explanatory lines. What matters is the usage line, and the fact that this takes a short name, not an owner-qualified repository name.
List installed extensions before picking a name. This does not contact a repository or change anything:
$ gh extension list
Extension Repository Version
owner/gh-extension, the documented short name is extension.gh extension exec cannot run something that is not installed. Install one through your normal review process, then come back.Replace EXTENSION_NAME with the exact short name from the previous step:
$ gh extension exec EXTENSION_NAME
For example, an installed repository owner/gh-label with short name label becomes:
$ gh extension exec label
The extension's own output comes straight back to your terminal, so what counts as success is extension-specific. In a script, check the exit status instead of the output:
$ gh extension exec EXTENSION_NAME
$ status=$?
$ printf 'extension exit status: %s\n' "$status"
extension exit status: 0
Status 0 means the program reported success, not that it did what you intended. Read its output and verify any remote change in GitHub before you move on.
Everything after the extension name goes straight to that extension's own executable. Name first, then its options and operands:
$ gh extension exec EXTENSION_NAME --input /path/to/input.txt --format table
Those option names belong to the extension's interface, not to gh extension exec itself. Check the individual extension's own help before using them, usually by forwarding its help flag:
$ gh extension exec EXTENSION_NAME --help
Quote paths and values that might contain spaces:
$ gh extension exec EXTENSION_NAME --file "/path/to/a file.txt"
Warning: do not build the argument list by concatenating untrusted text. A value with shell metacharacters can be interpreted by your shell before gh even sees it. Use shell arrays when arguments are assembled programmatically.
This is the whole reason the subcommand exists. An extension can share a short name with a built-in command: calling the name directly picks the core command, while the explicit form picks your extension:
$ gh label
# the core gh label command, if available
$ gh extension exec label
# the installed extension whose short name is label
Those two outputs are not shown as fixed text on purpose, because they depend on your CLI version, authentication and the particular extension. Verify the second command actually starts the extension you expect before putting it in a workflow.
If GitHub CLI says it cannot find an extension, do not immediately reinstall it or reach for sudo. Compare the name with the installed list first:
$ gh extension list
$ gh extension exec EXTENSION_NAME
# inspect the reported name and exit status
Common causes: a misspelled short name, using owner/gh-extension instead of extension, or assuming an extension exists because its repository is visible online. A non-zero status from the extension itself is a different problem from a lookup failure: in that case, the extension ran and rejected its own arguments.
When the output is unclear, run the extension's own help and capture its status:
$ gh extension exec EXTENSION_NAME --help
$ printf 'help exit status: %s\n' "$?"
Recovery: this does not undo a remote action, because help should only print usage. Treat any extension option that writes, deletes or changes repository state as a separate, deliberate operation with its own confirmation and recovery plan. gh extension exec has no undo mechanism for whatever the child extension actually does.
gh extension list.gh extension exec ran the extension you meant.