Triage GitHub Issues from the Shell with gh search issues

Forty browser tabs of half-remembered issues is no way to find the one bug report you need. With gh search issues you can build repeatable searches, narrow them by repository, state, label and date, and check the result as JSON. The examples use GitHub CLI 2.87.3 on Linux, and about fifteen minutes is plenty if gh is already authenticated.

Warning: do not put a token in a query, shell history or article example.

1. Check the installed command

Confirm the binary and version before relying on an option. This is an ordinary, unprivileged check:

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

The option set belongs to the installed release. A newer or older GitHub CLI may add or change fields, so keep this check near the start of scripts and troubleshooting notes.

Checkpoint: read the command's own synopsis and JSON field list.

$ gh search issues --help
Usage: gh search issues [ <query> ] [flags]

JSON FIELDS
  assignees, author, authorAssociation, body, closedAt, commentsCount,
  createdAt, id, isLocked, isPullRequest, labels, number, repository,
  state, title, updatedAt, url

2. Start with words or a quoted phrase

Arguments after gh search issues become search terms. Separate words are combined, while a quoted phrase keeps its spaces together:

$ gh search issues readme typo
$ gh search issues "broken feature"

The first query looks for both words. The second searches for the phrase. GitHub search still applies its normal matching rules, so neither promises an exact text match in every field. Use --match=title, --match=body or --match=comments when the location matters.

Tip: do not add sudo. The command reads remote search results and needs no protected local files.

3. Narrow the search with flags

Flags suit conditions common enough to deserve a named option. This finds open issues assigned to the authenticated user:

$ gh search issues --assignee=@me --state=open --limit 20

--limit controls the maximum number fetched and defaults to 30. It is not a page size for an existing result set. Set it deliberately in scripts so a later default change cannot alter the amount of work.

Repository and owner filters combine with ordinary terms:

$ gh search issues "cache invalidation" --repo OWNER/REPOSITORY --state=open
$ gh search issues --owner=github --archived=false --limit 50

Replace OWNER/REPOSITORY with a real repository. The owner form searches repositories owned by that account or organisation. The --archived=false example is explicit because archived repositories are otherwise included by the installed command's search behaviour.

Other useful filters: --label, --author, --milestone, --language, --created, --updated, --comments, --reactions and --locked. Check the value shape with gh search issues --help rather than guessing.

4. Pass GitHub search qualifiers safely

GitHub's search syntax can express conditions that have no dedicated flag. For example, this finds issues that do not have the bug label:

$ gh search issues -- -label:bug

The -- tells the local command-line parser that the remaining value is a query argument. Without it, a query beginning with a hyphen can be mistaken for a gh option. Use the same boundary for other negative qualifiers:

$ gh search issues -- "repo:OWNER/REPOSITORY is:open -label:bug"
$ gh search issues -- "in:title regression state:open"

Quote the complete query when it contains spaces, operators or punctuation. For a simple query, separate arguments read more easily. GitHub documents qualifiers such as repo:, is:, label:, author:, assignee:, created: and updated:. Use the official syntax when a query needs more than the flags expose.

5. Include pull requests only when you mean to

Issue search normally returns issues. Add --include-prs when pull requests should be part of the result:

$ gh search issues --include-prs --owner=cli --limit 10

Do not infer the type from the title. In a JSON result, inspect isPullRequest. If you need only issues while using a broad qualifier query, add the documented is:issue qualifier after the query boundary:

$ gh search issues -- "repo:OWNER/REPOSITORY is:open is:issue"

Tip: this distinction stops a pull request being counted as an issue in reports or triage scripts.

6. Make output suitable for scripts

Human-readable output is convenient at a terminal but a poor interface for automation. Ask for named JSON fields and select one property with the installed jq integration:

$ gh search issues --repo OWNER/REPOSITORY --state=open --limit 10 \
    --json number,title,state,url \
    --jq '.[] | "#\(.number) \(.state): \(.title) \(.url)"'
#123 open: Example issue title https://github.com/OWNER/REPOSITORY/issues/123

The result number and title above are illustrative. Your repository determines the actual values. JSON field names are case-sensitive and must be listed in gh search issues --help. Keep the query and formatting expression in separate shell words or quote them carefully, because a misplaced quote can change the query before it reaches GitHub.

For a first verification, omit --jq and inspect the raw JSON:

$ gh search issues --repo cli/cli --state=open --limit 1 \
    --json number,title,url
[{"number":14511,"title":"Use the tracked organization-owned fork as the pull request head","url":"https://github.com/cli/cli/issues/14511"}]

Checkpoint: that live check confirms the request, the selected fields and the authentication path. An empty array is a valid result, not automatically a failure.

7. Diagnose the common failure modes

If the command reports an authentication or permission error, check the current account without printing credentials:

$ gh auth status

Sign in or select the correct host using your normal organisation process. Do not paste a token into a command line. If a public query works but a private repository does not, check repository visibility and account access before changing search syntax.

Tip: the --sort option accepts fields such as created, updated, comments and reactions, and defaults to best-match. --order matters only when a sort is selected and defaults to desc. State those choices in a report so a reader can reproduce the ordering.

Done means