← All playbooks
CI/CD migration

Azure DevOps → GitHub Actions

Move Azure Pipelines YAML, Classic builds, releases, variables, agents, and approvals into GitHub Actions without treating an importer pull request as a finished cutover.

Typical timeline15–40 business days60–140 hours active work
Statusneeds review
Source profileAzure DevOps documentation reviewed 2026-10-25
Destination profileGitHub Actions documentation reviewed 2026-10-25
Documentation date
Review window
Evidence3 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

Azure DevOps

Reasons to stay
  • Repos, boards, pipelines, artifacts, and enterprise controls are tightly integrated
  • Repository-centered workflows keep code, review, and automation close together
Reasons to leave
  • The interface and administration model can feel heavy outside Microsoft-centric organizations
  • Advanced governance and automation can become configuration-heavy
New platform

GitHub Actions

What gets better
  • Automation lives beside the repository with an enormous reusable action ecosystem
  • Repository-centered workflows keep code, review, and automation close together
What gets worse
  • Large workflows can become slow, opaque, and expensive to debug
  • Advanced governance and automation can become configuration-heavy
Best of the move

GitHub Actions: Automation lives beside the repository with an enormous reusable action ecosystem. This removes a major source-side concern: The interface and administration model can feel heavy outside Microsoft-centric organizations.

Worst of the move

What you lose: Repos, boards, pipelines, artifacts, and enterprise controls are tightly integrated. What you inherit: Large workflows can become slow, opaque, and expensive to debug.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome11 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 5, Manual rebuild: 4, Not transferred: 2.
Clean0
Partial5
Manual4
Lost2
Mapping route9 of 9 fields have a destination path

This timeline assumes

  • Up to 150 pipelines, 40 shared templates, and 60 agents
  • Azure DevOps Services or Server 2019 or later, because the importer needs API version 5.0.
  • Repository, security, and release owners approve equivalent pipeline behavior.
  • Destination workflows stay disabled until source deploy queues drain.
  • The migration team records evidence for every blocking verification check.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
YAML build pipelines through Actions Importerpartialcriticalgh actions-importer can audit an organization, dry-run a pipeline, and open a pull request with converted YAML. Successful conversions still leave a Manual steps list. Partially successful pipelines convert structure but miss individual items.Run audit, forecast, dry-run, and migrate per project. Review every pull request before merge.
Classic editor pipelinesmanualcriticalGitHub Actions has no graphical editor. Microsoft says only Classic build designer pipelines can export to YAML, and you must be on the definition, not a run. Classic release pipelines do not support YAML export.Export supported Classic builds to YAML first. Rewrite Classic releases as GitHub workflows by hand.
Secrets, service connections, and environmentslostcriticalGitHub lists organization, repository, and environment secrets, plus service connections, as manual tasks. Values must never travel inside converted YAML.Recreate and rotate credentials as GitHub secrets or OIDC. Rebuild Environments with the same reviewers.
Self-hosted agents and approvalsmanualcriticalSelf-hosted agents, environments, and pre-deployment approvals do not convert. Pre-deployment gates, post-deployment gates, and post-deployment approvals are unsupported. Some resource triggers are unsupported.Build labeled GitHub runners and GitHub Environments before you enable deploy jobs.
Unknown tasks and implicit checkoutpartialhighUnknown tasks stay unconverted. Implicit Azure DevOps checkout can appear in the audit as a GUID. GitHub documents a task-GUID lookup URL on the Azure DevOps organization.Resolve every GUID and unknown task in the audit before you trust a green workflow.
Jobs, scripts, and Windows shellspartialcriticalGitHub maps script, bash, and pwsh to run plus shell. Azure Pipelines defaults Windows scripts to cmd. GitHub Actions defaults Windows to PowerShell. Azure can fail a script on stderr. GitHub does not.Set shell: cmd where the old script needs Command Prompt. Compare exit behavior on a rehearsal branch.
Stages, dependsOn, and conditionspartialcriticalAzure stages do not become one GitHub workflow. GitHub asks you to split stages into separate workflow files. dependsOn becomes needs. condition functions such as eq become infix if expressions.Draw the stage graph first. Test each condition with the same inputs you used in Azure DevOps.
Templates and shared stepsmanualcriticalAzure template files and task groups become reusable workflows or composite actions only after you pin a target repository. The importer can write a config.yml that lists those targets.Inventory every template. Pin reusable workflows and review GITHUB_TOKEN permissions.
Variable groups, schedules, and time zonesmanualhighClassic UI variables must be redefined in GitHub. Microsoft notes that YAML schedules use UTC, while Classic schedules used the organization time zone.Rewrite every cron in UTC and test the first fire. Recreate variable groups as environments or vars.
Build history and job logslostmediumThe importer writes conversion files, not past Azure DevOps logs. Forecast reads completed runs only to estimate Actions usage.Archive required logs and release evidence before the source becomes read-only.
Dual-CI deploy racespartialcriticalA converted workflow that still has deploy jobs can ship the same commit Azure DevOps is shipping.Keep GitHub deploy jobs disabled until Azure queues drain, then switch once.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
Azure Pipelines YAML jobGitHub Actions jobtransformGitHub requires explicit job structure.
script, bash, pwsh, or PowerShell taskrun step with shelltransformWindows defaults change from cmd to PowerShell.
taskActiontransformUnknown tasks stay manual.
dependsOnneedstransformPreserve fan-out and fan-in order.
conditionif expressiontransformReplace eq and and with infix operators.
pool or demandsruns-on labelmanualCreate missing self-hosted labels first.
Variable group or secretGitHub variable or secretmanualRotate values. Do not paste them into YAML.
Environment and pre-deployment approvalGitHub EnvironmentmanualGates do not convert.
Template or task groupReusable workflow or composite actionmanualPin the target repository from config.yml.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Preserve Azure Pipelines definitions, variables, agents, and release evidence before any GitHub write.

  1. Export YAML pipelines and, where the definition allows it, Classic builds as YAML.
  2. Inventory variable groups, service connections, environments, approvals, agents, and schedules.
  3. Archive recent job logs, artifact names, and release evidence.
  4. Hash configuration exports and record pipeline IDs.

Proof to capture: A signed manifest reconciles every scoped pipeline, secret consumer, runner, and export hash.

Transformation · gh actions-importer audit and forecast

Importer audit and forecast

See what converts, what stays manual, and how much Actions time you will burn.

  1. Run gh actions-importer audit azure-devops --output-dir tmp/audit.
  2. Read audit_summary.md for successful, partial, unsupported, and failed pipelines.
  3. Run forecast against recent completed jobs before you size runners.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · Importer dry-run plus a rehearsal branch

Dry-run and dual-CI harness

Prove artifact and deploy equivalence before GitHub owns production.

  1. Dry-run each active build and release pipeline.
  2. Run the same revision on Azure DevOps and GitHub.
  3. Compare artifacts, tests, and deploy side effects.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Pilot

An importer pull request ships a different artifact

criticalpossible likelihood

The workflow is green while dependencies, shells, or packaging differ.

Consequence
A bad build reaches users.
Mitigation
Compare checksums, tests, and provenance on the same commit.

Stop if: A critical artifact or test result differs.

Cutover

Both systems deploy the same commit

criticalpossible likelihood

Azure DevOps and GitHub both start a release job.

Consequence
Deployments race or run twice.
Mitigation
Disable GitHub deploy jobs until Azure queues drain, then switch once.

Stop if: Any source deployment can still start after ownership moves.

Security

A converted workflow can reach production secrets

criticalpossible likelihood

A pull-request job from a fork or a wide environment inherits a deploy secret.

Consequence
Build compromise becomes production compromise.
Mitigation
Use Environment protection and least-privilege secrets. Test a denied path.

Stop if: A test job can read an unauthorized secret or network.

06Precise timeline

Do the work in this order.

Estimate forUp to 150 pipelines, 40 shared templates, and 60 agents
Total elapsed15–40 business days
Active work60–140 hours
BufferAdd time for Classic releases, monorepos, self-hosted fleets, or a long dual-CI window.
01
Days 1–4Inventory and decisions3–4 days
02
Days 4–7Backup and audit2–3 days
03
Days 7–24Map and pilot8–16 days
04
Days 20–35Final delta and switch1–5 days
05
Days 22–50Observe and close4–12 days
  1. Days 1–4 · inventory

    Inventory and decisions

    8–16 hours active3–4 days elapsedOwner review waiting
    • Inventory YAML, Classic, templates, agents, secrets, and environments.
    • Approve which pipelines convert, rewrite, or retire.

    Depends on: Azure DevOps and GitHub Actions administrator access

    Stop / go checkpoint

    Export?

    Go when: Every critical pipeline has an owner and disposition.

    Stop when: API version, Classic coverage, or secret ownership is unclear.

  2. Days 4–7 · backup

    Backup and audit

    6–12 hours active2–3 days elapsedAudit container run waiting
    • Export pipeline YAML and Classic definitions.
    • Run the importer audit and reconcile pipeline IDs.

    Depends on: Approved inventory

    Stop / go checkpoint

    Transform?

    Go when: Audit coverage matches the inventory.

    Stop when: Any production pipeline is missing from the audit.

  3. Days 7–24 · pilot

    Map and pilot

    20–70 hours active8–16 days elapsedDual-CI comparison waiting
    • Dry-run a quiet repository, then shared templates.
    • Run Azure DevOps and GitHub on the same revisions and compare artifacts.

    Depends on: Verified backup

    Stop / go checkpoint

    Scale?

    Go when: Pilot mappings, artifacts, access, and evidence pass.

    Stop when: Any critical check fails or a GUID task is still unknown.

  4. Days 20–35 · cutover

    Final delta and switch

    6–24 hours active1–5 days elapsedQueue drain waiting
    • Disable Azure DevOps deploy jobs after queues drain.
    • Enable GitHub as the only automation platform and run blocking checks.

    Depends on: Passed pilot and approved rollback

    Stop / go checkpoint

    Open production?

    Go when: GitHub alone starts approved work.

    Stop when: A source writer remains active or a blocking check fails.

  5. Days 22–50 · observe

    Observe and close

    4–20 hours active4–12 days elapsedOne release cycle waiting
    • Monitor one complete build and release cycle.
    • Sign the verification report before you close rollback.

    Depends on: Verified cutover

    Stop / go checkpoint

    Close rollback?

    Go when: No trigger occurs during the agreed observation period.

    Stop when: Build, deploy, or access results regress.

07The point of change

Cut over with a way back.

Go live

Cutover

Make GitHub Actions the only production automation system without a dual deploy.

Recommended window: A low-volume weekday morning with platform, security, and release owners available.

  1. Drain Azure DevOps deploy queues and disable production pipelines.
  2. Enable the approved GitHub workflows and protected environments.
  3. Switch service connections, deploy keys, and release integrations to GitHub.
  4. Run every blocking check and keep Azure DevOps readable.
  5. Keep the source intact through the rollback window.

Proof to capture: GitHub Actions owns production automation, artifacts reconcile, and every blocking check has evidence.

Return to safety

Rollback

Return production automation to Azure DevOps without losing GitHub-era changes.

Deadline: Within seven days and before Azure DevOps plans, credentials, or agents are changed.

  1. Stop new GitHub deploy workflows.
  2. Restore Azure DevOps schedules, deploy jobs, and service connections.
  3. Export GitHub post-cutover workflow and release evidence.
  4. Review and apply safe destination-era changes to Azure DevOps.
  5. Run the same blocking checks against Azure DevOps.

Proof to capture: Azure DevOps again owns production automation with current configuration and no duplicate GitHub deploy.

Rollback immediately when
  • Unexplained artifact or test variance
  • Missing or exposed secrets
  • Duplicate production deploy
  • Failed access, runner, or environment check
  • A critical pipeline has no safe GitHub replacement
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingPipeline coverageReconcile every active Azure DevOps pipeline to a GitHub workflow or a retirement.Every pipeline has one approved disposition.Pipeline ledger.
V-02BlockingCommand and test parityRun identical revisions and inputs on both systems.Required tests and exit behavior match.Run comparison.
V-03BlockingBinary equivalenceCompare checksums, metadata, and retention.Approved artifacts match.Artifact report.
V-04BlockingEvent and schedule behaviorExercise push, pull request, manual, and cron paths, including workflow_dispatch string inputs.One correct run per approved event.Trigger log.
V-05BlockingEnvironment and capacityTest tools, network, isolation, and peak concurrency.Jobs run within approved security and time objectives.Runner report.
V-06BlockingSecrets and environmentsRun allowed and denied access tests, including a pull-request job.Least privilege and no secret disclosure.Security evidence.
V-07BlockingApprovals and deploymentRun a controlled staging and production release.Gates, concurrency, rollback, and notifications pass.Release evidence.
V-08BlockingSingle automation platformInspect Azure DevOps queues, schedules, and service hooks.GitHub Actions alone starts approved work.Cutover checklist.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: One complete build and release cycle, at least seven stable days, and owner sign-off on every blocking check.

  1. Archive Azure DevOps YAML, audit output, and verification evidence.
  2. Revoke migration PATs, importer tokens, and unused service connections.
  3. Remove obsolete Azure DevOps schedules, variable groups, and unused agents.
  4. Keep Azure DevOps readable through the approved retention window.
  5. Cancel paid Azure DevOps pipeline plans only after billing, legal, and recovery review.
  6. Schedule the next GitHub Actions backup, access, and playbook review.
10Experiences from the field

When the plan met reality.

First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.

First-person accountJames Dawson · endjin

Adventures in GitHub Actions Ep 1: from Azure DevOps to GitHub Actions2023

endjin principal James Dawson wrote that the company had already moved open-source repos to GitHub while CI still ran in Azure DevOps. Sporadic trigger and status bugs across PAT, OAuth, and GitHub App connections pushed them to move CI in 2023. They waited on reusable workflows and composite actions so they could replace shared Azure DevOps templates for .NET builds. The first concrete gotcha: workflow_dispatch inputs are strings, so a boolean checkbox had to be compared to 'true' before it could be passed to a reusable workflow. The 4 May 2026 update keeps that typing note in place.

What they recommend
  • Inventory shared Azure DevOps templates before you convert one repository, because reusable workflows are the replacement for that layer.
  • When a top-level workflow_dispatch value feeds a typed reusable workflow, compare the string to 'true' instead of passing the input through.
Worth noticing
  • The move started because GitHub-to-Azure DevOps plumbing kept breaking, not because YAML would not convert.
  • Reusable workflows closed the feature gap they had been waiting on.
First-person accountJamie Rees · Exclaimer Engineering

Decade of Code: A Journey from Azure DevOps to GitHub2024

Jamie Rees wrote that Exclaimer reviewed about 180 Azure DevOps repositories and migrated about 140. A proof of concept on a quiet UI repo imported git with GitHub's importer, then hit pipeline work. GitHub Actions Importer brought steps across but missed shared work such as installing .NET, security scanning, and version bumps, so they rewrote pipelines by hand. They replaced path reviewers with CODEOWNERS, tried Dependabot, then chose Renovate for the monorepo. A Curiosity Week team ran the cutover. After engineers returned, they reported no issues on the production codebase. The post covers repos plus CI, not Actions alone.

What they recommend
  • Treat the Actions Importer pull request as a draft. Rewrite shared templates yourself and compare a quiet repository first.
  • If you have Classic pipelines, budget a manual rewrite. Exclaimer said those could not be migrated automatically.
Worth noticing
  • The importer was useful for a first YAML shape and weak on the shared .NET steps they ran everywhere.
  • They pruned unused repositories before the migration week, which cut the work from 180 to about 140.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. GitHub: migrate Azure DevOps with Actions ImporterAccessed 2026-10-25
  2. GitHub: migrate from Azure Pipelines by handAccessed 2026-10-25
  3. Microsoft: export a Classic pipeline to YAMLAccessed 2026-10-25