I needed to find all the places in our GitHub org that were using a deprecated GitHub Actions runner label. We were migrating from runs-on: self-hosted to runs-on: ${{ vars.RUNNER_STANDARD }}, and I needed to find every workflow file that still used the old pattern. The gh search code command is perfect for this kind of organisation-wide search.
Basic search:
gh search code 'pattern' --owner my-org
Search in a specific path:
gh search code 'runs-on: self-hosted' --owner my-org -- path:.github
Get JSON output:
gh search code 'pattern' --owner my-org --json repository,path
The -- separator is important if your search term has special characters.
Open results in the browser:
gh search code 'pattern' --owner my-org --web
Exclude certain patterns using NOT:
gh search code '"vars.RUNNER" NOT RUNNER_STANDARD' --owner my-org
The quoting is fiddly. Double quotes inside single quotes work for exact matches.
Real example: finding deprecated runner labels Link to heading
Here’s what I actually ran to find all our deprecated runner configurations:
gh search code 'runs-on: self-hosted' --owner my-org -- path:.github/workflows
This found 47 workflow files across 23 repositories. I then refined it to exclude files that had already been migrated:
gh search code '"runs-on: self-hosted" NOT RUNNER_STANDARD' --owner my-org
This narrowed it down to 12 files that still needed updating. Much better than manually checking every repo.
Search syntax tips Link to heading
The search syntax is based on GitHub’s code search, which has some quirks:
Exact phrase matching: Use double quotes
gh search code '"exact phrase"' --owner my-org
Boolean operators: Use AND, OR, NOT (must be uppercase)
gh search code 'kubernetes AND docker' --owner my-org
gh search code 'TODO NOT FIXME' --owner my-org
Path filtering: Use path: or -- path: (the -- separator is recommended)
gh search code 'pattern' --owner my-org -- path:.github/workflows
gh search code 'pattern' --owner my-org -- path:*.py
Language filtering: Search only in specific languages
gh search code 'function' --owner my-org -- language:javascript
File name matching: Use filename:
gh search code 'pattern' -- filename:Dockerfile
JSON output for scripting Link to heading
The --json flag is incredibly useful for automation:
gh search code 'deprecated-function' --owner my-org --json repository,path,url | \
jq -r '.[] | "\(.repository.name): \(.path)"'
This gives you a clean list of repository and file paths, which you can pipe into other tools or scripts.
Limits and gotchas Link to heading
- GitHub has rate limits on code search (10 requests per minute for authenticated users)
- Results are limited to 100 matches by default
- Private repositories require appropriate permissions
- Very common terms might timeout or return incomplete results
For very large searches across many repos, you might be better off cloning the repos and using ripgrep locally. But for most cases, gh search code is perfect.