GitHub Actions Importer: what it converts and what it leaves for you
GitHub Actions Importer is a GitHub CLI extension, gh actions-importer, that runs in Docker and converts pipelines from Azure DevOps, Bamboo, Bitbucket Pipelines, CircleCI, GitLab, Jenkins and Travis CI into GitHub Actions workflows. Its audit, forecast, dry-run and migrate commands inventory a CI server, estimate Actions usage, convert one pipeline to local files and open a pull request, while secrets, runners and unknown plugins or orbs remain manual.
You have more pipelines than you want to convert by hand, and you want to know which ones will convert cleanly before you promise a date. That is the job the Importer does best: it reads the CI server, converts every pipeline it can, and writes a report that sorts them by how much is left to do.
It is not a finished migration. GitHub's documentation sets the goal at 80% conversion per workflow and says every converted workflow should be inspected before it runs production work. This page covers each command, the files they write, the per-platform manual work, and the mapping details that change behavior.

Install it and configure credentials
The Importer is a container image plus a gh extension that drives it, so it needs Docker running and the GitHub CLI installed. It does not have to run on the CI server; it talks to it over the API.
configure prompts for a GitHub personal access token (classic) with the repo and workflow scopes, which migrate uses to open pull requests, plus the URL and token for your CI system, and writes them to .env.local. update pulls the latest image. The extension itself last tagged a release, v1.3.6, in October 2023; the converter ships in the image, so run update before each session.
gh extension install github/gh-actions-importer
gh actions-importer update
gh actions-importer configure
gh actions-importer versionWhich platforms, and how each names a pipeline
All seven platforms support all four planning and conversion commands. What differs is the subcommand and the flag that identifies one pipeline for dry-run and migrate.
| Platform | Subcommand | Names one pipeline with |
|---|---|---|
| Jenkins | jenkins | --source-url (the job URL) |
| GitLab, cloud or self-managed | gitlab | --namespace and --project |
| CircleCI | circle-ci | --circle-ci-project |
| Azure DevOps | azure-devops pipeline or release | --pipeline-id |
| Bamboo | bamboo build or deployment | --plan-slug or --deployment-project-id |
| Bitbucket Pipelines | bitbucket | --workspace and --repository |
| Travis CI | travis-ci | --travis-ci-repository |
Audit, then forecast
audit fetches every project on the server, converts each one and writes audit_summary.md beside the converted files. Pipelines land in four buckets: successful (everything converted), partially successful (the structure converted, some items did not), unsupported, and failed, which usually means the original was invalid or the token could not read it. Build steps are counted as known, unknown or unsupported, and a Manual tasks section lists the secrets and self-hosted runner labels you have to create. workflow_usage.csv lists the actions, secrets and runners each pipeline uses, which is the list a security review wants.
forecast reads completed runs, the previous seven days by default, and reports job count, execution time, queue time and concurrent jobs. Execution time is your minutes estimate and concurrent jobs is your runner count. On Jenkins it needs the paginated-builds plugin installed first.
gh actions-importer audit jenkins --output-dir tmp/audit
gh actions-importer audit gitlab --output-dir tmp/audit --namespace my-group
gh actions-importer audit circle-ci --output-dir tmp/audit --include-from repositories.txt
gh actions-importer forecast jenkins --output-dir tmp/forecastWhat it converts, and what it leaves for you
Each platform guide on docs.github.com publishes a supported-syntax table and a list of constructs you must migrate manually. The manual lists are short and worth reading before the audit, because they predict most of the Manual steps section in every pull request.
| Platform | Converts | Left for you |
|---|---|---|
| Jenkins | Declarative stage, docker; partially agent, environment, steps, triggers, when. Not matrix, options, parameters or input | Scripted pipelines, secrets, self-hosted runners, unknown plugins, mandatory build tools |
| GitLab | script, needs, stages, tags, variables, image, resource_group, schedule; partially rules, only/except, include, services, parallel, environment | Masked project or group variable values, artifact reports; no caching between jobs of different workflows |
| CircleCI | Jobs, steps, executors to runs-on, matrix, when/unless, cron; partially orbs, container and services | Contexts, project-level environment variables, unknown job properties, unknown orbs; self-hosted executors unsupported |
Dry run with custom transformers
dry-run converts one pipeline and writes the workflow to disk. This is where you shape the output before anything reaches a repository. Custom transformers are Ruby files passed with --custom-transformers: runner maps a source label to an Actions label, env rewrites or removes a variable or points it at a secret, and transform replaces an unknown build step, such as a Jenkins shared library call, with steps you define.
Map runners first. The documentation states that a label the Importer cannot map becomes ubuntu-latest, and runner :default changes that fallback.
# transformers.rb
runner "linux", "ubuntu-latest"
runner "big-agent", ["self-hosted", "xl", "linux"]
runner :default, "ubuntu-latest"
env "REGISTRY_PASSWORD", secret("REGISTRY_PASSWORD")
transform "deployService" do |item|
{ name: "deploy", run: "./scripts/deploy.sh" }
end
# then:
# gh actions-importer dry-run jenkins --source-url https://jenkins.example.com/job/app \
# --output-dir tmp/dry-run --custom-transformers transformers.rbMigrate, and the mappings to check by hand
migrate runs the same conversion and opens a pull request against --target-url. Its description carries a Manual steps section, usually the secrets to create. Merge only after the first run on a branch is green.
Read the environment variable mappings before you trust a converted condition. The Importer maps Jenkins BUILD_NUMBER to github.run_id, a large unique id, not the per-workflow counter github.run_number, so image tags change shape. It maps GitLab CI_COMMIT_BRANCH and CircleCI CIRCLE_BRANCH to github.ref, which is refs/heads/main, so a comparison against main silently goes false. GitHub's sample list-features output also shows actions/cache and reusable-workflows disabled; check yours and turn them on with --enable-features if your target supports them.
gh actions-importer list-features
gh actions-importer migrate jenkins \
--source-url https://jenkins.example.com/job/app \
--target-url https://github.com/my-org/app \
--output-dir tmp/migrate \
--custom-transformers transformers.rb \
--enable-features actions/cacheKey takeaways
- Run audit across the server first; its four buckets are your migration order.
- forecast turns past runs into minutes and concurrency, the two numbers a runner choice needs.
- Secrets, runner labels, contexts and unknown plugins or orbs are always manual.
- Check converted conditions: branch variables map to the full
github.ref, andBUILD_NUMBERmaps togithub.run_id.
Frequently asked questions
Which CI platforms does GitHub Actions Importer support?
Does GitHub Actions Importer migrate secrets?
Can GitHub Actions Importer convert scripted Jenkins pipelines?
Does the Importer need to run on my CI server?
Related guides
References
- GitHub Docs: Automating migration with GitHub Actions Importer (read 2026-11-12)
- GitHub Docs: Extending GitHub Actions Importer with custom transformers
- GitHub Docs: Supplemental arguments and settings, including --features and --allowed-actions
- github/gh-actions-importer repository and releases
- GitHub Actions documentation