ISSUE 2026-09-27SERIES BREC 23TYPE BRIEFgarnetgrid.com

The direction of travel is not neutral

Insights

Both products belong to Microsoft, so no amount of comparison marketing will settle this one. The question worth asking is narrower and more awkward: which parts of Azure DevOps does your organisation actually depend on, what would it cost to replace each of them, and what happens to identity, CI and audit on the way across? Most of the answer is an inventory rather than an opinion, and the inventory usually points somewhere less dramatic than a migration programme.

Microsoft owns both products, which strips the competitive noise out of the comparison and leaves something more useful: a visible allocation of effort. The substantial new capabilities of recent years, and nearly all of the AI tooling, landed in GitHub first. Azure DevOps is maintained, supported and stable. It is not where the next five years of platform work is happening.

That is a reading of direction, not a quote from a roadmap, so check Microsoft's current statements rather than take mine. The consequence holds either way: treat Azure DevOps as a platform that will keep working and will not grow much.

It does not follow that you should migrate this quarter. It follows that you should stop starting things there. New repositories, new pipelines and above all new process customisation in Azure Boards are investments in a platform you will eventually leave.

Repositories are the easy part, which is why these migrations get mis-scoped

Both products serve Git, so unless TFVC survives somewhere the repository move is mechanical. A mirror push carries the history. LFS objects, submodules and anything unusually large need care. For most organisations this is days of scripting, not a programme.

The scope is everything attached to the repository: branch policies, service connections and the credentials inside them, pipeline definitions, artifact feeds, wikis, work item links embedded in thousands of commit messages, and webhooks nobody has thought about since they were configured.

The specific trap is classic pipelines. A pipeline built in the Azure DevOps UI has no YAML to read, its steps may be inline PowerShell, and its secrets were typed into a variable panel by someone who has since left. There is no translation tool for that because there is nothing to translate from. Count the classic definitions before anyone commits to a date. The number is usually well above the team's estimate.

Azure Boards is the part that is genuinely hard to replace

If you use Boards as a backlog, GitHub Issues and Projects will do. Projects has improved a great deal: custom fields, saved views, sub-issues, a roadmap layout.

What it does not have is a work item type system. An inherited process in Azure Boards defines types, each with its own fields and its own rules, so you can require a field in a particular state, set one automatically on transition, or hide it from a role. Fields in GitHub Projects belong to the project rather than to the item, and there are no per-type rules of that kind. Area and iteration paths, which many organisations use as a permission tree and a planning axis at once, have no direct equivalent either.

That distinction decides the project. If your delivery process is encoded in a Boards process template and an auditor has been shown that template, moving is a redesign of how you work, not a data migration.

Work item migration is also lower fidelity than people expect. You move items through an API, which creates new items: timestamps are rewritten, discussion threads flattened, attachments re-uploaded, link types approximated, and users who have left mapped to a placeholder. Ask whether you need the history live or archived. Archived is usually the honest answer and far cheaper.

Two other things have no counterpart. Azure Test Plans, if real people do manual test case management with traceability back to requirements, becomes a third-party purchase. And the Analytics service, with its queryable OData model, quietly backs more compliance reporting than most platform teams realise. GitHub offers a good GraphQL API and per-project insights, which is not the same shape. Anyone who built a report on OData is rewriting it.

Pipelines to Actions is a rewrite, and the cost model inverts underneath it

YAML in both, superficially similar, structurally different. Azure Pipelines composes tasks; Actions composes actions, and for a fair number of tasks there is no equivalent, only a shell script that does the same job. Templates and reusable workflows differ in scoping and in what a caller may override. Expect a rewrite, not a port.

The part worth doing properly is credentials. Both platforms support workload identity federation into Entra ID, so a pipeline receives a short-lived token instead of holding a secret. If you are rewriting anyway, come out of it with no stored cloud credentials at all.

Watch the approval model, because a control is easy to lose without noticing. Azure DevOps attaches checks to the protected resource: a service connection or an environment can demand approval, a time window, or an external gate, whichever pipeline reaches for it. Actions expresses similar intent through environments and rulesets, but the anchor point is different. Teams port the pipeline, skip the check, and the finding surfaces at the next audit.

The billing shape also inverts. Azure DevOps sells parallelism, a fixed number of concurrent slots, so overuse becomes a queue and an irritated developer. Actions bills runner time, with multipliers for non-Linux and larger machines, so overuse becomes an invoice. A matrix that fans out on every push to every branch is cheap to write and not cheap to run. I will not quote rates; they change and they are regional. The point is that a capacity limit has become a variable cost, and none of your existing habits will warn you. Self-hosted runners remove the per-minute charge and introduce a different problem.

Decide the identity model before a single repository moves

An Azure DevOps organisation is backed by an Entra tenant and that integration is mature: conditional access, group-based access, joiners and leavers handled where the rest of the estate handles them.

GitHub Enterprise Cloud offers two quite different shapes. Either SSO over personal GitHub accounts, or Enterprise Managed Users, where your identity provider creates and owns the accounts.

Managed users give you the lifecycle control an enterprise expects, and constrain developers in ways they will tell you about loudly. The account carries a suffixed handle, has no personal profile worth having, and cannot contribute to public repositories outside your enterprise. Engineers who maintain open source end up running two accounts and two browser profiles. The alternative is more pleasant and weaker: a personal account with SSO keeps the developer's identity intact, but off-boarding removes org membership rather than the account, and you are trusting an identity you do not own.

Settle it early because it behaves like a one-way door. As far as I know an existing enterprise cannot be converted to managed users in place; you stand up a new enterprise and migrate into it. Confirm that against current documentation, because if it still holds and you decide late, you migrate twice.

The security failure modes are different, not equivalent

Actions has one dominant class of vulnerability: untrusted input reaching a privileged context. The canonical form is a workflow triggered by pull_request_target, which runs the definition from the base branch with a write-scoped token and access to secrets, then checks out the pull request head and runs its build. A stranger's fork is now executing code with your credentials. The same pattern appears with comment triggers, and in expression injection, where something as ordinary as a pull request title is interpolated into a run: block.

The second class is supply chain. An action referenced by tag is a mutable reference, and tag retargeting against popular actions has happened in the wild. Pin third-party actions to a full commit SHA, let Dependabot move the pins, and restrict which actions are permitted at enterprise level. Azure Pipelines marketplace tasks carry comparable exposure with considerably less tooling around it, which is worth saying plainly: staying on Azure DevOps is not a supply chain control.

Self-hosted runners on any repository that accepts outside pull requests are a standing offer to run someone else's code on your network. If you need them there, make them ephemeral and isolate them.

One commercial note. GitHub's advanced security features have historically been metered against active committers rather than seats, and the packaging was re-cut recently. Committer count and seat count diverge sharply in a monorepo with a broad contributor base. Model it against your own commit graph, and take current packaging from GitHub, not from an article.

The hybrid is a legitimate destination, not a failure to finish

The configuration many enterprises land on is code and CI in GitHub with planning left in Azure Boards. It is supported deliberately: the Boards to GitHub connection links commits and pull requests to work items through an AB#123 mention, and Azure Pipelines can build GitHub repositories if you hold pipeline investment you are not ready to rewrite.

The price is two permission models and two audit trails, which is precisely how an organisation loses the ability to answer "who can deploy to production" in one sentence. Pick which system is authoritative for deployment authority and make the other structurally incapable of granting it. Then write down why the hybrid exists and what would end it. A hybrid you chose is cheaper than a redesign nobody asked for. A hybrid you drifted into over four years is neither.

Start by counting, because every argument here turns out to be about volume: how many classic pipeline definitions, how many work item types carry real rules, how many people hold Test Plans licences, whether any TFVC survives, who consumes the Analytics feed. That inventory usually settles the question without a debate. Then fix the identity model in writing before a repository moves. Migrate repository and CI together, one team at a time, leaving the old pipeline disabled rather than deleted for a fortnight. Keep Azure Boards until somebody can describe what replaces each rule you depend on. And treat "nothing new gets created in Azure DevOps" as the decision available this afternoon, with no migration budget at all. If nobody can name what is broken about the current setup, that is a finding too. Migrations justified only by the direction of a vendor's investment tend to cost more than the drift they were meant to prevent.

Talk to us about this